- my dotfiles are managed with a normal git repository at
~/projects/dotfiles. Use regulargitandtigfrom that repository. - commit every logical meaningful change after it was verified. stage individual hunks if necessary.
- I value simplicity, minimalism and elegance. YAGNI, KISS, SoC.
- automatically read relevant man pages and documentation websites before deciding or implementing anything
- before suggesting any config syntax, look up the official documentation to verify the syntax is correct
- configurations and programs should be resource friendly. Prefer rust(-script) over scripting languages. Allow the cpu to go into deep sleep states.
- the nixos and home manager configurations should be the source of truth
- when switching the current system, make sure to stay on the same specialization. You can simply use the already existing
switchscript. - automatically read analyze relevant log files and/or run commands like journalctl to get them
- you can assume all binaries in the nix store exist when referencing like this: "${pkgs.mypackage}/bin/mycommand"
- never search or grep the full nix store
- you can read specific files and dirs, like ~/bin or ~/.config IN $HOME, but not list files in home
- use
nixos-optionto find nixos options, e.g. services.xserver.xkb.layout - to figure out what exactly some software is doing, trace the nix build down to the source code.
- use DeepWiki MCP to answer questions about some repository
- for package investigations on flake-based systems, treat
flake.lockas the source of truth for the pinned nixpkgs revision - when tracing a package, prefer querying the pinned flake input directly with
nix flake metadata --json .andnix eval --impure --expr '(builtins.getFlake (toString ./.)).inputs.nixpkgs...'instead of assuming this repo exportspackagesorlegacyPackages - when
nix evalon a local path flake usesbuiltins.getFlake (toString ./.), add--impure - if
nix evalor related commands fail on/nix/var/nix/daemon-socket/socket, immediately rerun with escalation instead of working around it - prefer this package tracing order: config reference -> pinned flake input -> package metadata via
nix eval-> nixpkgs package definition or generated index -> installed runtime files -> upstream source/issues/PRs - for
pkgs.gnomeExtensions.*, checkpkgs/desktops/gnome/extensions/extensions.jsonandbuildGnomeExtension.nixbefore assuming there is a dedicated*.nixpackage file - for GNOME extensions, note that nixpkgs
versionmay be the extensions.gnome.org build number, while the human-facing extension version may live in embedded metadata likeversion-name - if a
src.outPathstore path is not realized or readable, inspect the pinned nixpkgs source tree and the installed runtime files under/run/current-system/swor/etc/profiles/per-user/...instead - for live desktop investigations, prefer checking the actually installed runtime files and session state, not just the derivation metadata
- if desktop debugging touches live GNOME session state, expect
gnome-extensions,dconf, and/run/user/*access to require escalation - If a nix let binding is reused across the whole module, keep it in the top-level let.
- If it is only used by one option block, move it into a local let right above that block.
- Prefer the narrowest scope that still keeps the code readable.
- for refactorings, use nvd to verify that the generated nix code is exactly the same before and after and only shows the desired changes. When comparing specializations, anchor on
/nix/var/nix/profiles/system/specialisation/<name>— not/run/current-system/specialisation/<name>, which only resolves when the parent toplevel is booted (checkcat /run/nixos/current-specialisationto see which spec is active). - to know how other people configure something, search their dotfiles on github. Use corresponding file path and language where appropriate.
- if you found a good reference or documentation for the task at hand, add a comment in the code referring to that documentation for future quick retreival
- If code should be moved to another file, always do it with shell commands to preserve the content verbatim and avoid copy paste errors
- If any command is missing to to the job or investigate, you can access any command via an ad-hoc nix-shell
- always add comments to document why things are the way they are. The comments should only refer to the current code, not to past code.
- don't hardcode paths. whenever possible, use xdg dirs.
- build incrementally during refactors, to catch errors early
- if a task is not straightforward, think about which refactor would make the task easy. Then do this refactoring first and commit it before attempting the task.
- once the user confirms a specific change is working, commit that change immediately (stage only the relevant hunks). Don't bundle it with later work or wait for more confirmations.
- never run
switch,nixos-rebuild switch, or any other system-activating rebuild yourself — the user always runs those manually.nixos-rebuild build(no activation) is fine for verification. - files written at runtime (not by nix) must carry a header comment naming the writer and the source template, e.g.
AUTOGENERATED at runtime by noctalia from home/noctalia/templates/<file>. Edits are overwritten on the next theme change.JSON files and other formats without comment support are exempt. - agents are configured in modules/home-manager/profiles/ai-agents/
- pi extensions are nix-managed: drop a *.ts into modules/home-manager/profiles/ai-agents/pi-extensions/ and pi-extensions.nix symlinks it into ~/.pi/agent/extensions/ (auto-discovered by pi;
/reloadto pick up changes) - pi extensions are gated by a reproducible check (pi-extensions-check.nix): tsgo type-check + oxlint +
node --test, type-checked against the pinned pi's own type declarations. Run it explicitly withnix build .#checks.x86_64-linux.pi-extensions(ornix flake check). It also gates store-mode packaging, so a type/lint/test error failsswitch/nixos-rebuild build; extensions listed inmy.devLinksbypass the packaging gate (edit-live) but are still covered by the explicit run. Keep unit-testable logic in a purecore.tswith a*.test.ts(node:test); collect tools in arrays via pi'sdefineTool()to preserve param inference. - sandboxing is done with nono. all ai agents are wrapped by default by nono. home/config/nono/profiles/agent.json.
- nono sandboxing should only allow what is necessary and disallow everything (except network access) by default. if some software needs access to a path that contains secrets/keys or critical information, suggest a safer way, so the agent gains the capability, but never sees the secrets. look at the nono docs for possibilities.
- the sandbox should limit ai agent compromitation and reduce attack surface for supply chain attacks.
- ssh keys should never rest in the file system. always per secret service in keepassxc.
- the agent must never read sensitive keys directly; broker the capability instead, the way ssh-agent does. e.g. for wireless adb to android devices, run the key-holding
adb -a nodaemon serveroutside the sandbox bound to the LAN ip (nono isolates loopback but shares the LAN interface) and have the sandboxed client reach it viaADB_SERVER_SOCKET=tcp:<host-lan-ip>:5037— the agent speaks only the wire protocol and never sees~/.android/adbkey. - when organizing nix architecture: prefer separate modules over options -> less coupling
- I use neo keyboard layout. The keys iale (form arrow cross for left hand) vs ngrt (form arrow cross for right hand)
configuration entrypoints:
- flake.nix # top-level NixOS flake
- hosts-nixos//default.nix # host NixOS configuration
- hosts-nixos//home.nix # host Home Manager configuration
- Each desktop is a NixOS specialisation built by
modules/nixos/specialisation-helpers.nix, which setsmy.desktop(andmy.themefor themed desktops) vialib.mkForce. Boot picks one;switch [<spec>]switches. - ALL desktop modules are imported unconditionally (e.g. both
desktops/herbstluftwm.nixanddesktops/noctalia-niri.nixinhosts-nixos/<host>/home.nix), then each guards its whole body withlib.mkIf (desktop == "<name>"). Only the matching desktop's block is active per specialisation, so home-manager config IS effectively spec-scoped even though the imports are shared. - Practical consequence: settings placed inside a
lib.mkIf (desktop == "X")block (e.g.xresources.propertiesfor the X11 desktop) only land in that specialisation's generation — they do not leak into other desktops. - Display managers differ per desktop: herbstluftwm uses lightdm (its
session-wrappersources~/.xprofile, runsxrdb -merge ~/.Xresources, theneval exec ~/.xsessionto launch the WM — so~/.Xresources/ home-managerxresources.propertiesare merged); noctalia-niri uses greetd runningniri-sessiondirectly, which never runsxrdb, so X resources are inert there.
- My friend Johannes has his private dotfiles repository here: git@github.com:cornerman/nixos.git (do temporary clones in /tmp)