proper repo

This commit is contained in:
Zoty 2026-05-22 15:51:43 -03:00
parent 33d01daa3d
commit 8a35a32445
Signed by: Zoty
SSH key fingerprint: SHA256:WsGEGivgl37t3Mth6uugXMOgMCTR7QolIepNbC+j/tA
17 changed files with 338 additions and 109 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

11
.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
# Nix build outputs
result
result-*
# direnv cache
.direnv/
# Editor artifacts
.vscode/
*.swp
*.swo

49
Justfile Normal file
View file

@ -0,0 +1,49 @@
# List all available recipes
default:
@just --list
# Rebuild and switch to the new configuration (uses current hostname by default)
switch hostname=`hostname`:
sudo nixos-rebuild switch --flake .#{{hostname}}
# Build without switching — useful to check the result before applying
build hostname=`hostname`:
nixos-rebuild build --flake .#{{hostname}}
# Apply the new configuration temporarily (reverts on next boot)
test hostname=`hostname`:
sudo nixos-rebuild test --flake .#{{hostname}}
# Update all flake inputs to their latest locked versions
update:
nix flake update
# Update a single flake input (e.g. just update-input nixpkgs)
update-input input:
nix flake update {{input}}
# Check the flake for evaluation errors
check:
nix flake check
# Open a Nix REPL with the flake loaded
repl:
nix repl --expr 'builtins.getFlake (toString ./.)'
# Delete Nix store paths older than 7 days and run the garbage collector
gc:
sudo nix-collect-garbage --delete-older-than 7d
nix-collect-garbage --delete-older-than 7d
# List all system generations
generations:
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
# Edit the SOPS-encrypted secrets file
secrets:
sops secrets/secrets.yaml
# Show a diff between the running system and the current build
diff hostname=`hostname`:
nix build .#nixosConfigurations.{{hostname}}.config.system.build.toplevel --no-link
nvd diff /run/current-system $(nix path-info .#nixosConfigurations.{{hostname}}.config.system.build.toplevel)

84
README.md Normal file
View file

@ -0,0 +1,84 @@
# NixOS Configuration
Personal NixOS configuration using the [den](https://github.com/vic/den) framework (dendritic pattern).
## Hosts
| Hostname | Profile | GPU |
|------------|----------------------|--------|
| `desktop` | Gaming + development | Nvidia |
| `notebook` | Portable development | Intel |
## Prerequisites
- [just](https://github.com/casey/just): `nix shell nixpkgs#just`
- [nvd](https://github.com/khumba/nvd) for `just diff`: `nix shell nixpkgs#nvd`
## Usage
```bash
# Rebuild and switch (uses current hostname automatically)
just switch
# Target a specific host
just switch desktop
just switch notebook
# Build only, without switching
just build
# Test (applies temporarily, reverts on next boot)
just test
# Update all inputs
just update
# Update a single input
just update-input nixpkgs
# Run garbage collection
just gc
# See what changed before switching
just diff
```
## Secrets (SOPS + age)
Secrets are stored encrypted in `secrets/secrets.yaml` and decrypted at boot by [sops-nix](https://github.com/Mic92/sops-nix).
### First-time setup on a new machine
1. Generate an age key:
```bash
mkdir -p /etc/sops/age
age-keygen -o /etc/sops/age/keys.txt
```
2. Add the new public key to `.sops.yaml` under `keys:`.
3. Re-encrypt secrets for all keys:
```bash
sops updatekeys secrets/secrets.yaml
```
### Adding a new secret
1. Edit the secrets file: `just secrets`
2. Declare it in `modules/secrets.nix` under `sops.secrets`.
### Rotating the age key
1. Generate a new key (step 1 above).
2. Update `.sops.yaml` with the new public key.
3. Run `sops updatekeys secrets/secrets.yaml` to re-encrypt.
## Identity
All user identity (name, email, SSH key) lives in `modules/identity.nix`. Override the defaults there or in a profile-specific module when creating a new user profile.
## Adding a new host
1. Run `nixos-generate-config` on the target machine and copy the output to `modules/_hardware/<hostname>-hardware.nix`.
2. Add the host in `modules/den.nix` under `den.hosts`.
3. Define or reuse an aspect for the host profile.

View file

@ -22,8 +22,16 @@
}; };
outputs = inputs: outputs = inputs:
(inputs.nixpkgs.lib.evalModules { let
modules = [ (inputs.import-tree ./modules) ]; system = "x86_64-linux";
specialArgs.inputs = inputs; pkgs = inputs.nixpkgs.legacyPackages.${system};
}).config.flake; flake = (inputs.nixpkgs.lib.evalModules {
modules = [ (inputs.import-tree ./modules) ];
specialArgs.inputs = inputs;
}).config.flake;
in flake // {
devShells.${system}.default = pkgs.mkShell {
packages = [ pkgs.just ];
};
};
} }

View file

@ -1,21 +1,15 @@
{ pkgs, ... }: { config, identity, pkgs, ... }: {
let
gitUsername = "Zoty";
gitEmail = "zotydev@gmail.com";
myPublicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8fKj0nQMJt9nnXbYgT4ggYuj6ieGCy6KL53frwoNHa";
in
{
home.packages = with pkgs; [ diff-so-fancy ]; home.packages = with pkgs; [ diff-so-fancy ];
home.file.".ssh/id_ed25519.pub".text = myPublicKey; home.file.".ssh/id_ed25519.pub".text = identity.sshPublicKey;
programs.git = { programs.git = {
enable = true; enable = true;
settings = { settings = {
user = { user = {
name = gitUsername; name = identity.fullName;
email = gitEmail; email = identity.email;
signingKey = "/home/zoty/.ssh/id_ed25519"; signingKey = "${config.home.homeDirectory}/.ssh/id_ed25519";
}; };
core = { core = {
compression = 9; compression = 9;
@ -29,8 +23,8 @@ in
}; };
init.defaultBranch = "main"; init.defaultBranch = "main";
status = { status = {
branch = true; branch = true;
showStash = true; showStash = true;
showUntrackedFiles = "all"; showUntrackedFiles = "all";
}; };
diff = { diff = {
@ -70,9 +64,9 @@ in
commit.gpgSign = true; commit.gpgSign = true;
gpg.format = "ssh"; gpg.format = "ssh";
url = { url = {
"git@github.com:ZotyDev/".insteadOf = "zoty:"; "git@github.com:ZotyDev/".insteadOf = "zoty:";
"git@github.com:UnnamedEngine/".insteadOf = "unen:"; "git@github.com:UnnamedEngine/".insteadOf = "unen:";
"git@github.com:Taumaturgo/".insteadOf = "taumaturgo:"; "git@github.com:Taumaturgo/".insteadOf = "taumaturgo:";
}; };
}; };
}; };

View file

@ -3,15 +3,14 @@ let
wallpaper = ../../wallpapers/miku.png; wallpaper = ../../wallpapers/miku.png;
in { in {
home.sessionVariables = { home.sessionVariables = {
XDG_SESSION_TYPE = "wayland"; XDG_CURRENT_DESKTOP = "niri";
XDG_CURRENT_DESKTOP = "niri"; XDG_SESSION_DESKTOP = "niri";
XDG_SESSION_DESKTOP = "niri"; QT_QPA_PLATFORM = "wayland;xcb";
QT_QPA_PLATFORM = "wayland;xcb"; QT_AUTO_SCREEN_SCALE_FACTOR = "1";
QT_AUTO_SCREEN_SCALE_FACTOR = "1"; QT_ENABLE_HIGHDPI_SCALING = "1";
QT_ENABLE_HIGHDPI_SCALING = "1"; QT_SCALE_FACTOR_ROUNDING_POLICY = "RoundPreferFloor";
QT_SCALE_FACTOR_ROUNDING_POLICY = "RoundPreferFloor";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
XDG_MENU_PREFIX = "plasma-"; XDG_MENU_PREFIX = "plasma-";
}; };
home.packages = with pkgs; [ home.packages = with pkgs; [
@ -26,7 +25,7 @@ in {
text = '' text = ''
#!/usr/bin/env bash #!/usr/bin/env bash
MODE="''${1:-region}" MODE="''${1:-region}"
SAVE_DIR="$HOME/Images/screenshots" SAVE_DIR="${config.xdg.userDirs.pictures}/screenshots"
mkdir -p "$SAVE_DIR" mkdir -p "$SAVE_DIR"
FILENAME="$SAVE_DIR/$(date '+%Y%m%d-%H%M%S').png" FILENAME="$SAVE_DIR/$(date '+%Y%m%d-%H%M%S').png"
@ -49,7 +48,6 @@ in {
config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/repos/nixos/quickshell"; config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/repos/nixos/quickshell";
xdg.configFile."niri/config.kdl".text = '' xdg.configFile."niri/config.kdl".text = ''
// Modificadores: Mod = Super (tecla Windows)
input { input {
keyboard { keyboard {
xkb { xkb {
@ -83,21 +81,21 @@ in {
spawn-at-startup "swww" "img" "${wallpaper}" "--transition-type" "none" spawn-at-startup "swww" "img" "${wallpaper}" "--transition-type" "none"
spawn-at-startup "quickshell" spawn-at-startup "quickshell"
screenshot-path "~/Imagens/screenshots/%Y-%m-%d %H-%M-%S.png" screenshot-path "${config.xdg.userDirs.pictures}/screenshots/%Y-%m-%d %H-%M-%S.png"
binds { binds {
// Aplicativos // Applications
Mod+Return { spawn "kitty"; } Mod+Return { spawn "kitty"; }
Mod+D { spawn "fuzzel"; } Mod+D { spawn "fuzzel"; }
Mod+Q { close-window; } Mod+Q { close-window; }
// Foco // Focus
Mod+Left { focus-column-left; } Mod+Left { focus-column-left; }
Mod+Right { focus-column-right; } Mod+Right { focus-column-right; }
Mod+Up { focus-window-up; } Mod+Up { focus-window-up; }
Mod+Down { focus-window-down; } Mod+Down { focus-window-down; }
// Mover janelas // Move windows
Mod+Shift+Left { move-column-left; } Mod+Shift+Left { move-column-left; }
Mod+Shift+Right { move-column-right; } Mod+Shift+Right { move-column-right; }
Mod+Shift+Up { move-window-up; } Mod+Shift+Up { move-window-up; }
@ -115,7 +113,7 @@ in {
Mod+Shift+4 { move-window-to-workspace 4; } Mod+Shift+4 { move-window-to-workspace 4; }
Mod+Shift+5 { move-window-to-workspace 5; } Mod+Shift+5 { move-window-to-workspace 5; }
// Sistema // System
Mod+Shift+E { quit; } Mod+Shift+E { quit; }
Mod+L { spawn "swaylock" "-i" "${wallpaper}" "--scaling" "fill"; } Mod+L { spawn "swaylock" "-i" "${wallpaper}" "--scaling" "fill"; }
@ -124,13 +122,13 @@ in {
XF86AudioLowerVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"; } XF86AudioLowerVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"; }
XF86AudioMute { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; } XF86AudioMute { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
// Zen mode (toggle quickshell bar) // Toggle quickshell bar (zen mode)
Mod+Z { spawn "quickshell" "ipc" "call" "zen" "toggle"; } Mod+Z { spawn "quickshell" "ipc" "call" "zen" "toggle"; }
// Input layout // Input layout
Mod+Space { switch-layout "next"; } Mod+Space { switch-layout "next"; }
// Screenshot // Screenshots
Mod+Shift+S { spawn "bash" "-c" "$HOME/.local/bin/screenshot region"; } Mod+Shift+S { spawn "bash" "-c" "$HOME/.local/bin/screenshot region"; }
Mod+Shift+Alt+S { spawn "bash" "-c" "$HOME/.local/bin/screenshot screen"; } Mod+Shift+Alt+S { spawn "bash" "-c" "$HOME/.local/bin/screenshot screen"; }
Mod+Shift+Ctrl+S { spawn "bash" "-c" "$HOME/.local/bin/screenshot monitor"; } Mod+Shift+Ctrl+S { spawn "bash" "-c" "$HOME/.local/bin/screenshot monitor"; }

View file

@ -0,0 +1,15 @@
{ config, ... }: {
xdg.userDirs = {
enable = true;
createDirectories = true;
desktop = "${config.home.homeDirectory}/Desktop";
download = "${config.home.homeDirectory}/Downloads";
templates = "${config.home.homeDirectory}/Templates";
publicShare = "${config.home.homeDirectory}/Public";
documents = "${config.home.homeDirectory}/Documents";
music = "${config.home.homeDirectory}/Music";
pictures = "${config.home.homeDirectory}/Pictures";
videos = "${config.home.homeDirectory}/Videos";
};
}

View file

@ -36,6 +36,7 @@
ncdu ncdu
unrar unrar
p7zip p7zip
nvd
]; ];
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
@ -46,11 +47,6 @@
programs.dconf.enable = true; programs.dconf.enable = true;
environment.sessionVariables = { environment.sessionVariables = {
XDG_SESSION_TYPE = "wayland";
CLUTTER_BACKEND = "wayland";
SDL_VIDEODRIVER = "wayland";
MOZ_ENABLE_WAYLAND = "1";
ELECTRON_OZONE_PLATFORM_HINT = "wayland";
EDITOR = "nvim"; EDITOR = "nvim";
}; };
}; };

26
modules/creative.nix Normal file
View file

@ -0,0 +1,26 @@
{ den, inputs, ... }: {
den.aspects.creative.nixos = { pkgs, ... }:
let
pkgs-unstable = import inputs.nixpkgs-unstable {
system = pkgs.system;
config.allowUnfree = true;
};
in {
environment.systemPackages = with pkgs-unstable; [
# 3D
blender
goxel
# Pixel art
aseprite
# Image editing
gimp
krita
# Video
obs-studio
kdePackages.kdenlive
];
};
}

View file

@ -1,4 +1,7 @@
{ inputs, den, lib, ... }: { { inputs, den, lib, config, ... }:
let
identity = config.local.identity;
in {
imports = [ inputs.den.flakeModule ]; imports = [ inputs.den.flakeModule ];
den.schema.user.classes = lib.mkDefault [ "homeManager" ]; den.schema.user.classes = lib.mkDefault [ "homeManager" ];
@ -18,9 +21,11 @@
includes = [ includes = [
den.provides.hostname den.provides.hostname
den.aspects.core den.aspects.core
den.aspects.wayland
den.aspects.niri den.aspects.niri
den.aspects.notebook-specific den.aspects.notebook-specific
den.aspects.dev den.aspects.dev
den.aspects.creative
den.aspects.secrets den.aspects.secrets
]; ];
nixos = { nixos = {
@ -32,9 +37,11 @@
includes = [ includes = [
den.provides.hostname den.provides.hostname
den.aspects.core den.aspects.core
den.aspects.wayland
den.aspects.niri den.aspects.niri
den.aspects.desktop-specific den.aspects.desktop-specific
den.aspects.dev den.aspects.dev
den.aspects.creative
den.aspects.secrets den.aspects.secrets
den.aspects.steam den.aspects.steam
den.aspects.prismlauncher den.aspects.prismlauncher
@ -62,7 +69,7 @@
useGlobalPkgs = true; useGlobalPkgs = true;
useUserPackages = true; useUserPackages = true;
backupFileExtension = "backup"; backupFileExtension = "backup";
extraSpecialArgs = { inherit inputs; }; extraSpecialArgs = { inherit inputs identity; };
}; };
security.sudo.wheelNeedsPassword = false; security.sudo.wheelNeedsPassword = false;
}; };
@ -74,6 +81,7 @@
./_home/git.nix ./_home/git.nix
./_home/dolphin.nix ./_home/dolphin.nix
./_home/theme.nix ./_home/theme.nix
./_home/xdg-dirs.nix
]; ];
}; };
}; };

View file

@ -14,7 +14,6 @@
}; };
nvidia = { nvidia = {
# Required by Wayland
modesetting.enable = true; modesetting.enable = true;
open = false; open = false;
nvidiaSettings = true; nvidiaSettings = true;
@ -44,13 +43,9 @@
}; };
environment.sessionVariables = { environment.sessionVariables = {
NIXOS_OZONE_WL = "1"; # Nvidia-specific Wayland backend overrides
GBM_BACKEND = "nvidia-drm"; GBM_BACKEND = "nvidia-drm";
__GLX_VENDOR_LIBRARY_NAME = "nvidia"; __GLX_VENDOR_LIBRARY_NAME = "nvidia";
MOZ_ENABLE_WAYLAND = "1";
MOZ_USE_XINPUT2 = "1";
__GL_SYNC_TO_VBLANK = "0";
__GL_MaxFramesAllowed = "1";
}; };
}; };
} }

View file

@ -1,51 +1,57 @@
{ den, inputs, pkgs, ... }: { { den, inputs, config, ... }:
let
username = config.local.identity.username;
in {
den.aspects.dev.nixos = { pkgs, ... }: den.aspects.dev.nixos = { pkgs, ... }:
let let
pkgs-unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}; pkgs-unstable = inputs.nixpkgs-unstable.legacyPackages.${pkgs.system};
in in {
{ environment.systemPackages = with pkgs-unstable; [
environment.systemPackages = (with pkgs-unstable; [ # CLI utilities
# Basic
gcc gcc
fzf fzf
just
tree-sitter tree-sitter
# LSPs
bash-language-server # Bash
lua-language-server # lua
nixd # Nix
vscode-langservers-extracted # Json & CSS
yaml-language-server # Yaml
dockerfile-language-server # Docker
marksman # Markdown
clang-tools # C++
jdt-language-server # Java
typescript-language-server # Typescript
pyright # Python
taplo # TOML and rust crates
sqls # SQL
astro-language-server # Astro
angular-language-server # Angular
vue-language-server # Vue
tailwindcss-language-server # Tailwind
qt6Packages.qtdeclarative # qmlls (QML/Quickshell LSP)
wgsl-analyzer
# Extra
chafa
ripgrep ripgrep
]) ++ (with pkgs; [ chafa
# Other
# Infrastructure
docker-compose
# IDE
jetbrains.idea-oss
# Neovim
vimPlugins.blink-cmp vimPlugins.blink-cmp
jetbrains.idea-community
aseprite # LSPs
goxel bash-language-server
]); lua-language-server
nixd
vscode-langservers-extracted
yaml-language-server
dockerfile-language-server
marksman
clang-tools
jdt-language-server
typescript-language-server
pyright
taplo
sqls
astro-language-server
angular-language-server
vue-language-server
tailwindcss-language-server
qt6Packages.qtdeclarative
wgsl-analyzer
];
programs.java = { programs.java = {
enable = true; enable = true;
package = pkgs.jdk17; package = pkgs-unstable.jdk17;
}; };
virtualisation.docker.enable = true; virtualisation.docker.enable = true;
users.users.zoty.extraGroups = [ "docker" ]; users.users.${username}.extraGroups = [ "docker" ];
}; };
} }

27
modules/identity.nix Normal file
View file

@ -0,0 +1,27 @@
{ lib, ... }: {
options.local.identity = {
username = lib.mkOption {
type = lib.types.str;
default = "zoty";
description = "Primary system username.";
};
fullName = lib.mkOption {
type = lib.types.str;
default = "Zoty";
description = "Full display name used in git and similar tools.";
};
email = lib.mkOption {
type = lib.types.str;
default = "zotydev@gmail.com";
description = "Primary email address.";
};
sshPublicKey = lib.mkOption {
type = lib.types.str;
default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8fKj0nQMJt9nnXbYgT4ggYuj6ieGCy6KL53frwoNHa";
description = "Primary SSH public key.";
};
};
}

View file

@ -34,13 +34,5 @@
efi.canTouchEfiVariables = true; efi.canTouchEfiVariables = true;
}; };
}; };
environment.sessionVariables = {
NIXOS_OZONE_WL = "1";
MOZ_ENABLE_WAYLAND = "1";
MOZ_USE_XINPUT2 = "1";
__GL_SYNC_TO_VBLANK = "0";
__GL_MaxFramesAllowed = "1";
};
}; };
} }

View file

@ -1,27 +1,26 @@
{ inputs, den, ... }: { { inputs, den, config, ... }:
let
username = config.local.identity.username;
in {
den.aspects.secrets.nixos = { ... }: { den.aspects.secrets.nixos = { ... }: {
imports = [ inputs.sops-nix.nixosModules.sops ]; imports = [ inputs.sops-nix.nixosModules.sops ];
sops = { sops = {
defaultSopsFile = ../secrets/secrets.yaml; defaultSopsFile = ../secrets/secrets.yaml;
# NOTE: This thing gave me a huge headache to setup. # Place your age keys at /etc/sops/age/keys.txt before deploying.
# If you are ME from future, don't forget to place # See README.md for setup instructions.
# your age keys here!
age.keyFile = "/etc/sops/age/keys.txt"; age.keyFile = "/etc/sops/age/keys.txt";
# Define secrets to be used.
secrets = { secrets = {
# Literally the user password.
"user-password" = { "user-password" = {
neededForUsers = true; neededForUsers = true;
}; };
# SSH private key.
"ssh-private-key" = { "ssh-private-key" = {
path = "/home/zoty/.ssh/id_ed25519"; path = "/home/${username}/.ssh/id_ed25519";
owner = "zoty"; owner = username;
mode = "0400"; mode = "0400";
}; };
}; };
}; };

20
modules/wayland.nix Normal file
View file

@ -0,0 +1,20 @@
{ den, ... }: {
den.aspects.wayland.nixos = {
environment.sessionVariables = {
# Core Wayland session
XDG_SESSION_TYPE = "wayland";
CLUTTER_BACKEND = "wayland";
SDL_VIDEODRIVER = "wayland";
# Browser / Electron Wayland backends
MOZ_ENABLE_WAYLAND = "1";
MOZ_USE_XINPUT2 = "1";
ELECTRON_OZONE_PLATFORM_HINT = "wayland";
NIXOS_OZONE_WL = "1";
# OpenGL / frame pacing
__GL_SYNC_TO_VBLANK = "0";
__GL_MaxFramesAllowed = "1";
};
};
}