Move the interactiveShellInit block and the copy function body into
modules/fish/*.fish and pull them in with builtins.readFile, so the
non-trivial fish lives in real fish files (highlighting, fish_indent)
instead of inline Nix strings. The Auto-loader only collects .nix, so
the new .fish files are ignored by it. Rendered config is unchanged.
Move the login-shell switch behind a new modules.fish.defaultShell
option (default false; neogaia opts in). Convert every non-eza alias to
an abbreviation, set preferAbbrs and pin generateCompletions, and switch
the command line to vi-style editing. Cap navigation at four dots and
drop psmem/psmem10/dir/vdir/please. Comment the installed packages.
Translate the CachyOS fish snapshot into a home-manager Module: the
fastfetch greeting, the bat-backed manpager, the done and bang-bang
plugins (from nixpkgs, not a plugin manager), the history/backup/copy
helper functions, and the eza and navigation aliases. Pacman-specific
aliases are dropped or replaced with NixOS equivalents (update ->
nixos-rebuild switch, cleanup -> nix-collect-garbage). Enabling the
Module also makes fish the user's default login shell.
Turn the booted laptop into a usable, remotely reachable console: enable
NetworkManager so wifi can be joined from the console and an SSH daemon so
the rest of the setup can be driven over the network. Set the base locale to
timezone America/New_York, locale en_GB.UTF-8, and console keymap us.
These live inline in the neogaia Host rather than behind enable Modules,
matching the single-Host MVI precedent; a shared locale/networking Module can
be extracted once a second Host needs the same settings. SSH keeps default
password auth on, as first-boot access relies on the hand-set bootstrap
password until key/sops-based auth lands post-install.
modules/zram.nix only wrapped the native zramSwap.enable toggle without
adding anything. Rewrite the touched comments to describe only the current
file content, and record the in-file-comment convention in CLAUDE.md.
Select the CachyOS kernel per-Host via boot.kernelPackages, enable Intel
microcode and redistributable firmware (ath10k for the QCA6174 wifi), and
move zram behind a toggle Module. Declare the chaotic binary cache in the
base Nix settings (extra-substituters/keys) so the built system fetches the
kernel from nyx-cache rather than compiling it.
Add disko as a flake input (following nixpkgs) and wire its NixOS module
into the host-builder, so any Host can declare a disk layout while the
layout itself stays a per-Host concern.
neogaia's layout (hosts/neogaia/disk.nix): one GPT NVMe disk with a
systemd-boot EFI system partition and a LUKS container holding btrfs with
@root/@home/@nix subvolumes. The initrd prompts for the passphrase on a
normal boot. Swap is RAM-backed zram, so there is no on-disk swap
partition; zramSwap is enabled directly for now. The placeholder
fileSystems are removed since disko now derives them.
In-file comments should describe only what the file currently is, not task
numbers, external tooling, or past/future states.
- hosts/neogaia: drop the "replaced by disko" / "arrive later" framing;
describe the filesystems and hardware profile as the placeholder values
they are.
- lib: drop the "no null-placeholder traversal hack" comparison to a prior
implementation.
- system: drop "no impure environment lookup" from the user.name description
and the sops/post-boot roadmap from the user comment.
26.05 is the latest stable NixOS release as of now (26.11 is still the
in-development branch that nixos-unstable reports); the previous 25.05 pin
was a release behind.
- flake.nix / flake.lock: stable overlay tracks nixos-26.05.
- neogaia system.stateVersion and the base home.stateVersion set to 26.05
(fresh install, so aligning to the current stable release).
- Refresh the "latest stable release" references in the project docs to
match.
Other inputs are rolling branches (nixos-unstable, nixpkgs-unstable,
chaotic nyxpkgs-unstable) or master (home-manager, per spec), so they carry
no version to bump.
Stand up the walking skeleton the rest of the laptop MVI extends and
re-verifies against: the whole neogaia Host evaluates and its system
toplevel builds (nix flake check green).
- flake.nix: hand-rolled flake (no flake-parts). Base nixos-unstable, plus
nixpkgs-unstable and nixos-25.05 for the per-package unstable/stable
overlays, home-manager (nixpkgs followed), and chaotic-nyx (deliberately
not following our nixpkgs, to keep its binary cache usable). checks build
each Host toplevel.
- lib/: trimmed helper lib — the Auto-loader (recursive .nix discovery, no
null-placeholder hack), the host-builder, and the script-from-file helper.
Deps inherited explicitly; no with lib.my, no nixosModules output.
- system/: shared base config — the unstable/stable overlays, the user
option (defaults to alexion, in wheel, drives system + home-manager user
in lockstep), flakes, git, and home-manager as a NixOS module.
- modules/example.nix: Auto-loader / Enable-convention reference Module,
inert until enabled.
- hosts/neogaia/: minimal laptop Host — placeholder filesystems, bootloader,
and hardware profile.
- CLAUDE.md: project agent instructions with a Gotchas section (nix on the
CachyOS dev host, the chaotic overlay/cache behaviour, the forge CLI).
Capture the design work for the NixOS migration before any implementation:
- .claude/CONTEXT.md: domain glossary (Host, Module, Skeleton, Auto-loader,
Enable convention, unstable/stable overlay)
- .claude/adr/0001-sops-nix-for-secrets.md: secrets tooling decision
- .claude/spec/laptop-mvi.md: frozen minimum-viable-install spec for neogaia
- reference/: read-only snapshot of the current CachyOS configs (secrets and
state excluded), plus ENVIRONMENT.md profiling the live environment to guide
replication
Add a PreToolUse hook that reminds the main agent not to author test
files directly, and change the implement skill to always use
test-driven-development rather than only where possible.
implement: sync main and cut task-<NNNN>-<slug> before work, with
stop-and-ask guards for a dirty tree, a diverged main, and an unmerged
blocker. Replaces the no-commit rule with one commit, a push, and a PR
carrying the review's Risk block plus any unaddressed findings.
test-driven-development: every test is written by a general-purpose
sub-agent that never reads the implementation; the main agent writes the
code and never edits a test.
Wire Stop and Notification hooks in ~/.claude/settings.json to a new
~/.claude/hooks/attention-bell.sh, which rings the terminal bell in the
session pane so tmux monitor-bell flags the background window.
The hook runs detached (no controlling tty), so it walks its process
ancestry to the claude process and writes the BEL to that pane tty.
Also replaces the dead settings.json symlink (pointed at a now-missing
~/wrk/claude path) with a real tracked file.
Adds a dot setup subcommand family (idempotent, re-runnable machine-setup
tasks) with a folders task that brings the 8 standard XDG user
directories under a fixed short-name convention (Desktop -> .desktop,
Documents -> doc, Downloads -> dwn, Music -> mus, Pictures -> pic,
Videos -> vid, Templates/Public -> .ignoreme), hardcoded rather than read
from ~/.config/user-dirs.dirs -- that file is a separate, manually
tracked dotfile whose values can drift or go stale, and the migration
must not depend on it being correct. The nested Pictures/Screenshots
folder is renamed to pic/screenshots in the same pass.
Content left behind in a legacy full-named folder by a fresh XDG-defaults
install -- empty or not -- is merged into its short-named replacement.
A same-named collision between a legacy folder and its target is never
overwritten: it is skipped, reported, and the legacy folder is left in
place rather than deleted while something in it could not be merged.
--dry-run previews what would move/skip without touching the filesystem.
xdg-user-dirs-update runs once afterward to notify running apps/portals.
dot kde save's tab-completion only ever enumerated schema-backed
identifiers; kglobalshortcutsrc identifiers never showed up as
candidates despite being a fully supported mechanism. Enumerate them
live via kglobalaccel (allMainComponents/allActionsForComponent),
printed as a separate block after the schema-backed one, degrading
silently if the D-Bus session is unavailable.
Dispatches kglobalshortcutsrc identifiers through the kglobalaccel D-Bus
service instead of the schema-backed or freeform rc-file paths. Verified
manually against the live session (per the spec's testing decision, this
mechanism is excluded from the automated suite); switched to the
shortcutKeys/defaultShortcutKeys/setShortcutKeys D-Bus methods after the
spec's originally-named shortcut/defaultShortcut/setShortcut proved to
return stale data on the live system. Moves Lock Session off Meta+L to
Meta+X as the real-world validation, tracked in the manifest and recorded
in keybindings.md.
Read/write schema-less KDE settings (e.g. kxkbrc's Options= line)
directly via kreadconfig6/kwriteconfig6, with default defined as the
key being absent. diff only checks freeform entries already declared
in the manifest, never via undeclared broad scan.
Brings the machine's caps-lock/Escape swap under tracking as the
real-world validation case.
Implements the broad, read-only schema-backed scan for dot kde diff:
walks every (rcfile, group, key) reachable through the kcfg mapping
table, compares live values against their schema-declared defaults,
and reports each mismatch tagged declared or undeclared. Never writes.
Also fixes dot kde completions, which only ever offered save/help —
apply (added in a prior task) and diff were both missing.
Pushes every manifest entry's declared value onto the live system via
kwriteconfig6, idempotently. Non-schema (shortcuts/freeform) entries are
rejected as not-yet-supported, deferred to later tasks.
Removed .config/dot/.tmp from tracking: it was an empty 0-byte file
that had been committed by accident on another machine and was never
meant to be part of the repo.
Recorded fish_variables as it stands after first boot on this machine:
fish stamped __fish_initialized with its own version marker
(bootstrap bookkeeping, not user config) alongside the already-tracked
pure prompt theme, done plugin settings, and fisher plugin
registration.
Introduces the dot kde subcommand family (fish dispatcher plus a Python
helper under commands/kde/), a flat identifier=value manifest, and
dot kde save in both its explicit-identifier and no-argument refresh
modes. Settings resolve to KDE's KConfigXT schema-backed mechanism via a
(rcfile -> [kcfg files]) mapping table auto-derived by scanning the
system schema directory (overridable via DOT_KDE_KCFG_DIR), plus a
hand-maintained exceptions list for schemas that only declare their
target rc file at runtime. Also wires tab-completion for dot kde save
identifiers, sourced live from that same mapping table.