me like nix
1{
2 pkgs,
3 inputs,
4 config,
5 ...
6}:
7
8{
9 # Import the home-manager modules you want to use
10 imports = [
11 inputs.catppuccin.homeModules.catppuccin
12 inputs.niri.homeModules.niri
13 inputs.zen-browser.homeModules.beta
14 inputs.agenix.homeManagerModules.default
15 ];
16
17 programs.niri = {
18 enable = true;
19 settings = {
20 window-rules = [
21 {
22 geometry-corner-radius = {
23 top-left = 5.0;
24 top-right = 5.0;
25 bottom-left = 5.0;
26 bottom-right = 5.0;
27 };
28 clip-to-geometry = true;
29 draw-border-with-background = false;
30 }
31 ];
32 debug = {
33 honor-xdg-activation-with-invalid-serial = { };
34 };
35 layout = {
36 focus-ring = {
37 width = 2;
38 active.color = "#8caaee";
39 inactive.color = "#414559";
40 };
41 struts = {
42 top = -6;
43 bottom = -6;
44 left = 0;
45 right = 0;
46 };
47 gaps = 8;
48 };
49 gestures = {
50 hot-corners = {
51 enable = false;
52 };
53 };
54 binds = {
55 "Mod+d".action.spawn = "fuzzel";
56 "Mod+e".action.spawn = "bemoji";
57 "Mod+n".action.spawn = "networkmanager_dmenu";
58 "Mod+a".action.spawn = "alacritty";
59 "Mod+h".action = {
60 focus-column-left = { };
61 };
62 "Mod+j".action = {
63 focus-workspace-down = { };
64 };
65 "Mod+k".action = {
66 focus-workspace-up = { };
67 };
68 "Mod+l".action = {
69 focus-column-right = { };
70 };
71 "Mod+Shift+h".action = {
72 move-column-left = { };
73 };
74 "Mod+Shift+j".action = {
75 move-window-down-or-to-workspace-down = { };
76 };
77 "Mod+Shift+k".action = {
78 move-window-up-or-to-workspace-up = { };
79 };
80 "Mod+Shift+l".action = {
81 move-column-right = { };
82 };
83 "Mod+Down".action = {
84 move-workspace-down = { };
85 };
86 "Mod+Up".action = {
87 move-workspace-up = { };
88 };
89 "Mod+p".action = {
90 show-hotkey-overlay = { };
91 };
92 "Mod+o".action = {
93 toggle-overview = { };
94 };
95 "Mod+q".action = {
96 close-window = { };
97 };
98 "Mod+f".action = {
99 toggle-window-floating = { };
100 };
101 "Mod+Shift+f".action = {
102 switch-focus-between-floating-and-tiling = { };
103 };
104 "Mod+m".action = {
105 fullscreen-window = { };
106 };
107 "Mod+s".action = {
108 screenshot = {
109 show-pointer = true;
110 };
111 };
112 "Mod+1".action = {
113 set-column-width = "100%";
114 };
115 "Mod+2".action = {
116 set-column-width = "50%";
117 };
118 "Mod+Minus".action = {
119 set-column-width = "-10%";
120 };
121 "Mod+Equal".action = {
122 set-column-width = "+10%";
123 };
124 "Mod+Shift+r".action.spawn = [
125 "sh"
126 "-c"
127 "pkill quickshell; quickshell &"
128 ];
129 "XF86MonBrightnessDown".action.spawn = [
130 "brightnessctl"
131 "set"
132 "5%-"
133 ];
134 "XF86MonBrightnessUp".action.spawn = [
135 "brightnessctl"
136 "set"
137 "+5%"
138 ];
139 };
140 outputs = {
141 # External monitor - primary display at position (0, 0)
142 "DP-5" = {
143 scale = 2.0;
144 mode = {
145 width = 5120;
146 height = 2160;
147 refresh = 120.0;
148 };
149 position = {
150 x = 0;
151 y = 0;
152 };
153 };
154 "DP-1" = {
155 scale = 2.0;
156 mode = {
157 width = 5120;
158 height = 2160;
159 refresh = 120.0;
160 };
161 position = {
162 x = 0;
163 y = 0;
164 };
165 };
166 "DP-2" = {
167 scale = 1.0;
168 mode = {
169 width = 5120;
170 height = 2160;
171 refresh = 120.0;
172 };
173 position = {
174 x = 0;
175 y = 0;
176 };
177 };
178 "DP-6" = {
179 scale = 2.0;
180 mode = {
181 width = 5120;
182 height = 2160;
183 refresh = 120.0;
184 };
185 position = {
186 x = 0;
187 y = 0;
188 };
189 };
190 "DP-7" = {
191 scale = 2.0;
192 mode = {
193 width = 5120;
194 height = 2160;
195 refresh = 120.0;
196 };
197 position = {
198 x = 0;
199 y = 0;
200 };
201 };
202 # Laptop display - secondary display positioned underneath
203 "eDP-1" = {
204 scale = 1.5;
205 mode = {
206 width = 2560;
207 height = 1600;
208 refresh = 165.0;
209 };
210 position = {
211 x = 0;
212 y = 1080; # Position underneath the external monitor (2160 / 2 scale = 1080 logical height)
213 };
214 };
215 };
216 spawn-at-startup = [
217 { command = [ "xwayland-satellite" ]; }
218 { command = [ "swww-daemon" ]; }
219 { command = [ "quickshell" ]; }
220 { command = [ "wl-paste --watch cliphist store" ]; }
221 ];
222 environment = {
223 DISPLAY = ":0";
224 };
225 };
226 };
227
228 # Allow unfree packages
229 nixpkgs.config.allowUnfree = true;
230
231 nixpkgs.config.permittedInsecurePackages = [
232 "libsoup-2.74.3"
233 ];
234
235 # Quickshell status bar
236 xdg.configFile."quickshell/shell.qml".source = ./quickshell/shell.qml;
237
238 programs.ssh = {
239 enable = true;
240 enableDefaultConfig = false;
241 matchBlocks = {
242 "*" = {
243 extraOptions = {
244 IdentityAgent = "${config.home.homeDirectory}/.1password/agent.sock";
245 };
246 };
247 };
248 };
249
250 programs.awscli = {
251 enable = true;
252 settings = {
253 "default" = {
254 region = "us-east-1";
255 };
256 };
257 };
258
259 # All your user-specific packages
260 home.packages = with pkgs; [
261 helix
262 git
263 jujutsu # jj-cli
264 htop
265 zellij # terminal multiplexer
266 alacritty
267 fuzzel # Application launcher
268 bemoji # emoji picker
269 networkmanager_dmenu # network picker for fuzzel
270 quickshell # Status bar (QML-based)
271 swww # For setting wallpapers
272 cliphist # Clipboard history manager
273 pavucontrol # GUI for PulseAudio/PipeWire volume control
274 fd
275 ripgrep
276 yazi # tui file browser
277 gh # github cli
278 signal-desktop
279 xwayland-satellite # for running x11 apps
280 nixfmt # nix formatter
281 nil # nix language server
282 atac # postman-like TUI
283 trippy # network analyzer
284 rsync # file sync utility
285 udiskie # for mounting external drives
286 darktable # photo editing
287 zoxide
288 chromium
289 claude-code
290 nautilus # file browser
291 sqlitebrowser
292 gnome-characters # symbol picker
293 sendme # file transfer
294 desktop-file-utils # for managing .desktop files
295 flyctl # fly.io cli
296 vscode-json-languageserver
297 gnome-network-displays
298 doppler # secret management
299 rainfrog # db tui
300 loupe # image viewer
301 glycin-loaders # various format loaders for loupe
302 docker-compose
303 discord
304 mangohud
305 prismlauncher # minecraft launcher
306 fastfetch
307 inputs.agenix.packages.${pkgs.system}.default # agenix CLI
308 age-plugin-yubikey # Yubikey support for agenix
309
310 # --- FONTS ARE IMPORTANT ---
311 # Berkeley Mono is the main system font, keeping JetBrains and Font Awesome for icons
312 font-awesome
313 noto-fonts
314 noto-fonts-cjk-sans
315 noto-fonts-color-emoji
316 nerd-fonts.jetbrains-mono
317 nerd-fonts.symbols-only
318 # --- POLKIT AGENT (for 1Password GUI, etc.) ---
319 lxqt.lxqt-policykit # Lightweight polkit agent
320 ];
321
322 services.udiskie = {
323 enable = true;
324 tray = "auto";
325 automount = true;
326 };
327
328 services.mako = {
329 enable = true;
330 settings = {
331 border-radius = 8;
332 border-size = 2;
333 padding = "12";
334 margin = "12";
335 font = "BerkeleyMono Nerd Font 11";
336 on-button-left = "invoke-default-action";
337 on-button-right = "dismiss";
338 };
339 };
340
341 catppuccin = {
342 enable = true;
343 flavor = "frappe";
344 };
345
346 programs.fuzzel.enable = true;
347
348 programs.direnv.enable = true;
349
350 programs.atuin = {
351 enable = true;
352 enableFishIntegration = true;
353 settings = {
354 filter_mode_shell_up_key_binding = "session";
355 };
356 };
357
358 programs.zellij = {
359 enable = true;
360 settings = {
361 keybinds = {
362 unbind = [
363 "Ctrl q"
364 "Ctrl o"
365 ];
366 normal = {
367 "bind \"Ctrl m\"" = {
368 SwitchToMode = "Session";
369 };
370 };
371 };
372 pane_frames = false;
373 show_startup_tips = false;
374 ui = {
375 pane_frames.hide_session_name = true;
376 };
377 };
378 };
379
380 programs.zen-browser.enable = true;
381 # programs.swww.enable = true;
382 programs.zoxide = {
383 enable = true;
384 enableFishIntegration = true;
385 };
386
387 programs.obs-studio = {
388 enable = true;
389 plugins = with pkgs.obs-studio-plugins; [
390 obs-backgroundremoval
391 ];
392 };
393
394 # Program configurations
395 programs.git = {
396 enable = true;
397 settings = {
398 user = {
399 name = "seanaye";
400 email = "hello@seanaye.ca";
401 };
402 init.defaultBranch = "main";
403 commit.gpgSign = true;
404 gpg.format = "ssh";
405 user.signingKey = "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOIgEteUEW06dnBHe2z8vNLwz2iMKe8bba6JgMmOUpcBAAAABHNzaDo= sean@framework16";
406 gpg.ssh.allowedSignersFile = "${config.home.homeDirectory}/.ssh/allowed_signers";
407 };
408 };
409 programs.jujutsu = {
410 enable = true;
411 settings = {
412 user = {
413 email = "hello@seanaye.ca";
414 name = "Sean Aye";
415 };
416 signing = {
417 sign-all = true;
418 behavior = "own";
419 backend = "ssh";
420 key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=";
421 backends.ssh.allowed-signers = "${config.home.homeDirectory}/.ssh/allowed_signers";
422 };
423 };
424 };
425
426 programs.home-manager.enable = true;
427
428 programs.fish = {
429 enable = true;
430 shellAliases = {
431 agenix = "agenix -i ~/.config/agenix/yubikey-identity.txt";
432 };
433 interactiveShellInit = ''
434 set fish_greeting
435 # Set 1Password SSH agent socket
436 set -gx SSH_AUTH_SOCK ${config.home.homeDirectory}/.1password/agent.sock
437 # Load 1Password CLI plugins
438 if test -f ~/.config/op/plugins.sh
439 source ~/.config/op/plugins.sh
440 end
441 # Show fastfetch when inside zellij
442 if set -q ZELLIJ
443 fastfetch --logo small
444 end
445
446 function y
447 set tmp (mktemp -t "yazi-cwd.XXXXXX")
448 yazi $argv --cwd-file="$tmp"
449 if read -z cwd < "$tmp"; and [ -n "$cwd" ]; and [ "$cwd" != "$PWD" ]
450 builtin cd -- "$cwd"
451 end
452 rm -f -- "$tmp"
453 end
454 '';
455 functions = {
456 s3edit = ''
457 set file (basename $argv[1])
458 set tmpfile /tmp/$file
459 aws s3 cp $argv[1] $tmpfile
460 and $EDITOR $tmpfile
461 and aws s3 cp $tmpfile $argv[1]
462 '';
463 };
464 };
465
466 programs.starship = {
467 enable = true;
468 enableFishIntegration = true;
469 };
470
471 programs.alacritty = {
472 enable = true;
473 settings = {
474 terminal.shell = {
475 program = "zellij";
476 args = [
477 "options"
478 "--on-force-close"
479 "detach"
480 ];
481 };
482 window = {
483 decorations = "none";
484 opacity = 0.9;
485 };
486 font = {
487 normal = {
488 family = "BerkeleyMono Nerd Font";
489 style = "Regular";
490 };
491 size = 12.0;
492 };
493 };
494
495 };
496
497 programs.helix = {
498 enable = true;
499 settings = {
500 editor = {
501 bufferline = "multiple";
502 file-picker = {
503 hidden = false;
504 git-ignore = true;
505 };
506 cursor-shape = {
507 insert = "bar";
508 normal = "block";
509 select = "underline";
510 };
511 line-number = "relative";
512 cursorline = true;
513 auto-format = true;
514 end-of-line-diagnostics = "hint";
515 soft-wrap = {
516 enable = true;
517 };
518 lsp = {
519 display-inlay-hints = true;
520 display-messages = true;
521 display-progress-messages = true;
522 };
523 inline-diagnostics = {
524 cursor-line = "hint";
525 };
526 };
527 keys = {
528 normal = {
529 esc = [
530 "keep_primary_selection"
531 "collapse_selection"
532 ];
533 };
534
535 };
536 };
537 languages = {
538
539 language-server.rust-analyzer = {
540 config = {
541 check = {
542 command = "clippy";
543 };
544 checkOnSave = true;
545 cargo = {
546 allFeatures = true;
547 };
548 };
549 };
550 language-server.deno-lsp = {
551 command = "deno";
552 args = [ "lsp" ];
553 config.deno.enable = true;
554 };
555
556 language = [
557 {
558 name = "html";
559 formatter = {
560 command = "prettier";
561 args = [
562 "--parser"
563 "html"
564 ];
565 };
566 }
567 {
568 name = "nix";
569 auto-format = true;
570 formatter = {
571 command = "${pkgs.nixfmt}/bin/nixfmt";
572 };
573 }
574 {
575 name = "kotlin";
576 auto-format = true;
577 }
578 {
579 name = "rust";
580 auto-format = true;
581 formatter = {
582 command = "rustfmt";
583 args = [
584 "--edition"
585 "2024"
586 ];
587 };
588 indent = {
589 tab-width = 4;
590 unit = "t";
591 };
592 }
593 {
594 name = "astro";
595 auto-format = true;
596 formatter = {
597 command = "npx";
598 args = [
599 "prettier"
600 "--plugin"
601 "prettier-plugin-astro"
602 "--parser"
603 "astro"
604 ];
605 };
606 }
607 {
608 name = "json";
609 auto-format = true;
610 }
611 {
612 name = "just";
613 auto-format = true;
614 formatter = {
615 command = "just";
616 args = [
617 "--justfile"
618 "/dev/stdin"
619 "--dump"
620 ];
621 };
622 }
623 {
624 name = "toml";
625 auto-format = true;
626 formatter = {
627 command = "taplo";
628 args = [
629 "format"
630 "-"
631 ];
632 };
633 }
634 # {
635 # name = "typescript";
636 # roots = [
637 # "deno.json"
638 # "deno.jsonc"
639 # ];
640 # file-types = [
641 # "ts"
642 # "tsx"
643 # ];
644 # auto-format = true;
645 # language-servers = [ "deno-lsp" ];
646 # }
647 ];
648 };
649 };
650
651 dconf.settings = {
652 "org/gnome/desktop/interface" = {
653 color-scheme = "prefer-dark";
654 enable-hot-corners = false;
655 };
656 };
657
658 # Font rendering configuration
659 fonts.fontconfig = {
660 enable = true;
661 defaultFonts = {
662 monospace = [ "BerkeleyMono Nerd Font" ];
663 sansSerif = [ "Noto Sans" ];
664 serif = [ "Noto Serif" ];
665 };
666 };
667
668 # Cursor configuration
669 home.pointerCursor = {
670 name = "Adwaita";
671 package = pkgs.adwaita-icon-theme;
672 size = 16;
673 x11.enable = true;
674 gtk.enable = true;
675 };
676
677 # Session variables
678 home.sessionVariables = {
679 EDITOR = "hx";
680 VISUAL = "hx";
681 SUDO_EDITOR = "hx";
682 SSH_AUTH_SOCK = "${config.home.homeDirectory}/.1password/agent.sock";
683 };
684
685 # SSH allowed signers for commit signature verification
686 home.file.".ssh/allowed_signers".text = ''
687 hello@seanaye.ca ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=
688 hello@seanaye.ca sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOIgEteUEW06dnBHe2z8vNLwz2iMKe8bba6JgMmOUpcBAAAABHNzaDo= sean@framework16
689 '';
690
691 # Yubikey identity for agenix (not secret - just a reference to the hardware key)
692 home.file.".config/agenix/yubikey-identity.txt".text = ''
693 # Serial: 26930059, Slot: 1
694 # Name: agenix
695 # Recipient: age1yubikey1qw64ag5lzvn9ekrflu5ruj4a6ucycscl6ctk39fjzf76jptsay39z442pxv
696 AGE-PLUGIN-YUBIKEY-1304E5QVZZD74FKSP8FMCT
697 '';
698
699 # Set the state version for Home Manager
700 home.stateVersion = "25.05";
701}