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 = 2.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 prismlauncher # minecraft launcher
305 fastfetch
306 inputs.agenix.packages.${pkgs.system}.default # agenix CLI
307 age-plugin-yubikey # Yubikey support for agenix
308
309 # --- FONTS ARE IMPORTANT ---
310 # Berkeley Mono is the main system font, keeping JetBrains and Font Awesome for icons
311 font-awesome
312 noto-fonts
313 noto-fonts-cjk-sans
314 noto-fonts-color-emoji
315 nerd-fonts.jetbrains-mono
316 nerd-fonts.symbols-only
317 # --- POLKIT AGENT (for 1Password GUI, etc.) ---
318 lxqt.lxqt-policykit # Lightweight polkit agent
319 ];
320
321 services.udiskie = {
322 enable = true;
323 tray = "auto";
324 automount = true;
325 };
326
327 services.mako = {
328 enable = true;
329 settings = {
330 border-radius = 8;
331 border-size = 2;
332 padding = "12";
333 margin = "12";
334 font = "BerkeleyMono Nerd Font 11";
335 on-button-left = "invoke-default-action";
336 on-button-right = "dismiss";
337 };
338 };
339
340 catppuccin = {
341 enable = true;
342 flavor = "frappe";
343 };
344
345 programs.fuzzel.enable = true;
346
347 programs.direnv.enable = true;
348
349 programs.atuin = {
350 enable = true;
351 enableFishIntegration = true;
352 settings = {
353 filter_mode_shell_up_key_binding = "session";
354 };
355 };
356
357 programs.zellij = {
358 enable = true;
359 settings = {
360 keybinds = {
361 unbind = [
362 "Ctrl q"
363 "Ctrl o"
364 ];
365 normal = {
366 "bind \"Ctrl m\"" = {
367 SwitchToMode = "Session";
368 };
369 };
370 };
371 pane_frames = false;
372 show_startup_tips = false;
373 ui = {
374 pane_frames.hide_session_name = true;
375 };
376 };
377 };
378
379 programs.zen-browser.enable = true;
380 # programs.swww.enable = true;
381 programs.zoxide = {
382 enable = true;
383 enableFishIntegration = true;
384 };
385
386 programs.obs-studio = {
387 enable = true;
388 plugins = with pkgs.obs-studio-plugins; [
389 obs-backgroundremoval
390 ];
391 };
392
393 # Program configurations
394 programs.git = {
395 enable = true;
396 settings = {
397 user = {
398 name = "seanaye";
399 email = "hello@seanaye.ca";
400 };
401 init.defaultBranch = "main";
402 };
403 };
404 programs.jujutsu = {
405 enable = true;
406 settings = {
407 user = {
408 email = "hello@seanaye.ca";
409 name = "Sean Aye";
410 };
411 signing = {
412 sign-all = true;
413 behavior = "own";
414 backend = "ssh";
415 key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=";
416 };
417 };
418 };
419
420 programs.home-manager.enable = true;
421
422 programs.fish = {
423 enable = true;
424 shellAliases = {
425 agenix = "agenix -i ~/.config/agenix/yubikey-identity.txt";
426 };
427 interactiveShellInit = ''
428 set fish_greeting
429 # Set 1Password SSH agent socket
430 set -gx SSH_AUTH_SOCK ${config.home.homeDirectory}/.1password/agent.sock
431 # Load 1Password CLI plugins
432 if test -f ~/.config/op/plugins.sh
433 source ~/.config/op/plugins.sh
434 end
435 # Show fastfetch when inside zellij
436 if set -q ZELLIJ
437 fastfetch --logo small
438 end
439
440 function y
441 set tmp (mktemp -t "yazi-cwd.XXXXXX")
442 yazi $argv --cwd-file="$tmp"
443 if read -z cwd < "$tmp"; and [ -n "$cwd" ]; and [ "$cwd" != "$PWD" ]
444 builtin cd -- "$cwd"
445 end
446 rm -f -- "$tmp"
447 end
448 '';
449 functions = {
450 s3edit = ''
451 set file (basename $argv[1])
452 set tmpfile /tmp/$file
453 aws s3 cp $argv[1] $tmpfile
454 and $EDITOR $tmpfile
455 and aws s3 cp $tmpfile $argv[1]
456 '';
457 };
458 };
459
460 programs.starship = {
461 enable = true;
462 enableFishIntegration = true;
463 };
464
465 programs.alacritty = {
466 enable = true;
467 settings = {
468 terminal.shell = {
469 program = "zellij";
470 args = [
471 "options"
472 "--on-force-close"
473 "detach"
474 ];
475 };
476 window = {
477 decorations = "none";
478 opacity = 0.9;
479 };
480 font = {
481 normal = {
482 family = "BerkeleyMono Nerd Font";
483 style = "Regular";
484 };
485 size = 12.0;
486 };
487 };
488
489 };
490
491 programs.helix = {
492 enable = true;
493 settings = {
494 editor = {
495 bufferline = "multiple";
496 file-picker = {
497 hidden = false;
498 git-ignore = true;
499 };
500 cursor-shape = {
501 insert = "bar";
502 normal = "block";
503 select = "underline";
504 };
505 line-number = "relative";
506 cursorline = true;
507 auto-format = true;
508 end-of-line-diagnostics = "hint";
509 soft-wrap = {
510 enable = true;
511 };
512 lsp = {
513 display-inlay-hints = true;
514 display-messages = true;
515 display-progress-messages = true;
516 };
517 inline-diagnostics = {
518 cursor-line = "hint";
519 };
520 };
521 keys = {
522 normal = {
523 esc = [
524 "keep_primary_selection"
525 "collapse_selection"
526 ];
527 };
528
529 };
530 };
531 languages = {
532
533 language-server.rust-analyzer = {
534 config = {
535 check = {
536 command = "clippy";
537 };
538 checkOnSave = true;
539 cargo = {
540 allFeatures = true;
541 };
542 };
543 };
544 language-server.deno-lsp = {
545 command = "deno";
546 args = [ "lsp" ];
547 config.deno.enable = true;
548 };
549
550 language = [
551 {
552 name = "html";
553 formatter = {
554 command = "prettier";
555 args = [
556 "--parser"
557 "html"
558 ];
559 };
560 }
561 {
562 name = "nix";
563 auto-format = true;
564 formatter = {
565 command = "${pkgs.nixfmt}/bin/nixfmt";
566 };
567 }
568 {
569 name = "kotlin";
570 auto-format = true;
571 }
572 {
573 name = "rust";
574 auto-format = true;
575 formatter = {
576 command = "rustfmt";
577 args = [
578 "--edition"
579 "2024"
580 ];
581 };
582 indent = {
583 tab-width = 4;
584 unit = "t";
585 };
586 }
587 {
588 name = "astro";
589 auto-format = true;
590 formatter = {
591 command = "npx";
592 args = [
593 "prettier"
594 "--plugin"
595 "prettier-plugin-astro"
596 "--parser"
597 "astro"
598 ];
599 };
600 }
601 {
602 name = "json";
603 auto-format = true;
604 }
605 {
606 name = "just";
607 auto-format = true;
608 formatter = {
609 command = "just";
610 args = [
611 "--justfile"
612 "/dev/stdin"
613 "--dump"
614 ];
615 };
616 }
617 {
618 name = "toml";
619 auto-format = true;
620 formatter = {
621 command = "taplo";
622 args = [
623 "format"
624 "-"
625 ];
626 };
627 }
628 # {
629 # name = "typescript";
630 # roots = [
631 # "deno.json"
632 # "deno.jsonc"
633 # ];
634 # file-types = [
635 # "ts"
636 # "tsx"
637 # ];
638 # auto-format = true;
639 # language-servers = [ "deno-lsp" ];
640 # }
641 ];
642 };
643 };
644
645 dconf.settings = {
646 "org/gnome/desktop/interface" = {
647 color-scheme = "prefer-dark";
648 enable-hot-corners = false;
649 };
650 };
651
652 # Font rendering configuration
653 fonts.fontconfig = {
654 enable = true;
655 defaultFonts = {
656 monospace = [ "BerkeleyMono Nerd Font" ];
657 sansSerif = [ "Noto Sans" ];
658 serif = [ "Noto Serif" ];
659 };
660 };
661
662 # Cursor configuration
663 home.pointerCursor = {
664 name = "Adwaita";
665 package = pkgs.adwaita-icon-theme;
666 size = 16;
667 x11.enable = true;
668 gtk.enable = true;
669 };
670
671 # Session variables
672 home.sessionVariables = {
673 EDITOR = "hx";
674 VISUAL = "hx";
675 SUDO_EDITOR = "hx";
676 SSH_AUTH_SOCK = "${config.home.homeDirectory}/.1password/agent.sock";
677 };
678
679 # Yubikey identity for agenix (not secret - just a reference to the hardware key)
680 home.file.".config/agenix/yubikey-identity.txt".text = ''
681 # Serial: 26930059, Slot: 1
682 # Name: agenix
683 # Recipient: age1yubikey1qw64ag5lzvn9ekrflu5ruj4a6ucycscl6ctk39fjzf76jptsay39z442pxv
684 AGE-PLUGIN-YUBIKEY-1304E5QVZZD74FKSP8FMCT
685 '';
686
687 # Set the state version for Home Manager
688 home.stateVersion = "25.05";
689}