{ inputs, lib, config, vars, pkgs, pkgs-unstable, ... }: { imports = [ # ./alacritty # ./conky # ./helix # ./lf # ./quickshell ./cargo ./chawan ./dunst ./firefox ./fish ./git ./hyprland ./hyprlock ./mail ./mpv ./newsboat ./nvim ./tenere ./ticker ./vale ./walker ./wallpapers ./waybar ]; age = { identityPaths = [ "${config.home.homeDirectory}/.ssh/id_ed25519" ]; secrets = { miniflux_api_key = { path = "${config.home.homeDirectory}/.secrets/miniflux_api_key"; file = ../secrets/miniflux_api_key.age; }; openai_auth_token.file = ../secrets/openai_auth_token.age; relesoft_cargo_token.file = ../secrets/relesoft_cargo_token.age; shiori_password.file = ../secrets/shiori_password.age; unsplash_access_key.file = ../secrets/unsplash_access_key.age; gmail = { file = ../secrets/gmail.age; path = "${config.home.homeDirectory}/.secrets/gmail"; mode = "600"; }; relesoft = { file = ../secrets/relesoft.age; path = "${config.home.homeDirectory}/.secrets/relesoft"; mode = "600"; }; }; }; gtk = { enable = true; theme = { package = pkgs.whitesur-gtk-theme; name = "WhiteSur-Dark"; }; iconTheme = { package = pkgs.nordzy-icon-theme; name = "Nordzy"; }; font = { package = pkgs.roboto-flex; name = "Roboto Flex 11"; }; }; qt = { enable = true; style = { package = pkgs.darkly; name = "Darkly"; }; }; programs = { element-desktop = { enable = true; settings = { "m.homeserver" = { base_url = "https://matrix.relesoft.io"; server_name = "relesoft.io"; }; default_theme = "dark"; }; }; zellij = { # modern tmux enable = true; enableFishIntegration = false; }; zoxide = { # smarter cd command enable = true; enableFishIntegration = true; enableNushellIntegration = true; }; nushell = { enable = true; extraConfig = '' $env.config.hooks.command_not_found = source ${pkgs.nix-index}/etc/profile.d/command-not-found.nu let carapace_completer = {|spans| carapace $spans.0 nushell ...$spans | from json } $env.config = { show_banner: false, completions: { case_sensitive: false # case-sensitive completions quick: true # set to false to prevent auto-selecting completions partial: true # set to false to prevent partial filling of the prompt algorithm: "fuzzy" # prefix or fuzzy external: { enable: true max_results: 100 completer: $carapace_completer # check 'carapace_completer' } } } $env.PATH = ($env.PATH | split row (char esep) | prepend /home/petri/.apps | append /usr/bin/env ) ''; }; carapace = { enable = true; enableNushellIntegration = true; enableFishIntegration = true; }; gpg = { enable = true; settings = { no-comments = true; }; }; fzf = { enable = true; enableFishIntegration = true; # use CTRL+t for files, CTRL + r for history defaultOptions = [ "--style full" "--preview '${pkgs.pistol}/bin/pistol {}'" ]; }; yazi = { # file browser enable = true; enableNushellIntegration = true; enableFishIntegration = true; settings = { manager = { show_hidden = true; show_symlink = true; }; preview = { image_filter = "lanczos3"; image_quality = 90; }; }; }; atuin = { enable = true; enableFishIntegration = true; enableNushellIntegration = true; daemon = { enable = true; }; settings = { auto_sync = true; sync_address = "https://atuin.tammi.cc"; sync_frequency = "5m"; style = "compact"; workspaces = true; }; }; starship = { enable = true; enableFishIntegration = true; enableTransience = true; enableNushellIntegration = true; }; eza = { enable = true; enableFishIntegration = true; enableNushellIntegration = true; git = true; icons = "auto"; extraOptions = [ "--color=always" "--tree" "--level=1" "--group-directories-first" "--dereference" ]; }; nix-index = { enable = true; enableFishIntegration = true; }; pistol.enable = true; ghostty = { enable = true; installVimSyntax = true; enableFishIntegration = true; settings = { font-family = "Iosevka Nerd Font"; font-size = 12; mouse-hide-while-typing = true; copy-on-select = true; theme = "nord"; }; themes = { nord = { background = "#2e3440"; foreground = "#d8dee9"; selection-background = "#3f4758"; selection-foreground = "#d8dee9"; cursor-color = "#d8dee9"; cursor-text = "#2e3440"; palette = [ "0=#3b4252" "1=#bf616a" "2=#a3be8c" "3=#ebcb8b" "4=#81a1c1" "5=#b48ead" "6=#88c0d0" "7=#e5e9f0" "8=#4c566a" "9=#bf616a" "10=#a3be8c" "11=#ebcb8b" "12=#81a1c1" "13=#b48ead" "14=#8fbcbb" "15=#eceff4" ]; }; }; }; ssh = { enableDefaultConfig = false; enable = true; matchBlocks."*" = { serverAliveInterval = 1; compression = true; controlMaster = "auto"; controlPersist = "10m"; }; }; chromium = { enable = true; package = pkgs.chromium; commandLineArgs = [ "--load-media-router-component-extension=1" "--enable-features=VaapiVideoDecodeLinuxGL,VaapiVideoEncoder,Vulkan,VulkanFromANGLE,DefaultANGLEVulkan,VaapiIgnoreDriverChecks,VaapiVideoDecoder,PlatformHEVCDecoderSupport,UseMultiPlaneFormatForHardwareVideo" "--enable-features=UseOzonePlatform --ozone-platform=wayland" "--enable-media-router" "--enable-smooth-scrolling" "--force-dark-mode" ]; dictionaries = [ pkgs.hunspellDictsChromium.en_US ]; extensions = [ # vimium # https://chromewebstore.google.com/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb "dbepggeogbaibhgnhhndojpepiihcmeb" # bitwarden # https://chromewebstore.google.com/detail/bitwarden-password-manage/nngceckbapebfimnlniiiahkandclblb "nngceckbapebfimnlniiiahkandclblb" # ublock origin lite # https://chromewebstore.google.com/detail/ublock-origin-lite/ddkjiahejlhfcafbddmgiahcphecmpfh "ddkjiahejlhfcafbddmgiahcphecmpfh" # decentraleyes # https://chromewebstore.google.com/detail/decentraleyes/ldpochfccmkkmhdbclfhpagapcfdljkj "ldpochfccmkkmhdbclfhpagapcfdljkj" # redeck # https://chromewebstore.google.com/detail/readeck/jnmcpmfimecibicbojhopfkcbmkafhee?pli=1 "jnmcpmfimecibicbojhopfkcbmkafhee" ]; }; home-manager.enable = true; }; services = { mpd-mpris.enable = true; mpd = { enable = true; musicDirectory = "/media/skydrive/Music/"; extraArgs = [ "--verbose" ]; network = { listenAddress = "any"; startWhenNeeded = true; port = 6600; }; }; psd = { enable = true; backupLimit = 5; }; gpg-agent = { defaultCacheTtl = 1800; enable = true; enableFishIntegration = true; enableSshSupport = true; pinentry.package = pkgs.pinentry-gnome3; }; mpris-proxy.enable = true; clipse = { enable = true; }; }; manual = { html.enable = true; json.enable = true; }; home = { enableNixpkgsReleaseCheck = true; stateVersion = "25.05"; shell = { enableFishIntegration = true; enableNushellIntegration = true; }; username = "${vars.user}"; sessionVariables = { CC = "clang"; BROWSER = "${pkgs.firefox}/bin/firefox"; CARGO_REGISTRIES_RELESOFT_CREDENTIAL_PROVIDER = "cargo:token"; CARGO_REGISTRIES_RELESOFT_INDEX = "sparse+https://git.relesoft.io/api/packages/relesoft/cargo/"; CARGO_REGISTRIES_RELESOFT_IO_PROTOCOL = "sparse"; CARGO_REGISTRIES_RELESOFT_TOKEN = "$(${pkgs.coreutils}/bin/cat ${config.age.secrets.relesoft_cargo_token.path})"; CURSOR_SIZE = "16"; DEFAULT_BROWSER = "${pkgs.firefox}/bin/firefox"; ELECTRON_OZONE_PLATFORM_HINT = "auto"; GDK_SCALE = "1"; MOZ_USE_XINPUT2 = "1"; NIXOS_OZONE_WL = "1"; PAGER = "${pkgs.nvimpager}/bin/nvimpager"; PISTOL_CHROMA_FORMATTER = "terminal256"; PISTOL_CHROMA_STYLE = "monokai"; VISUAL = "${pkgs.neovim}/bin/nvim"; OPENAI_API_KEY = "$(${pkgs.coreutils}/bin/cat ${config.age.secrets.openai_auth_token.path})"; SHIORI_PASSWORD = "$(${pkgs.coreutils}/bin/cat ${config.age.secrets.shiori_password.path})"; }; pointerCursor = { package = pkgs.bibata-cursors; gtk.enable = true; name = "Bibata-Modern-Ice"; size = 22; }; homeDirectory = "/home/${vars.user}"; packages = with pkgs; [ # tui tools bluetui # bluetooth management chawan # browser, currently crashes clipse # clipboard management impala # iwd terminal ui lux # youtube-downloader pkgs-unstable.nom # rss reader rmpc # tui for mpd rtorrent # torrent starship # shell aid systemctl-tui tenere # llm tui ticker # stock ticker wthrr # weather forecast from openmeteo yazi # file manager # gui bitwarden-desktop # password mananger ghostty # terminal emulator hypridle hyprlock hyprpaper libreoffice lxqt.pavucontrol-qt obsidian # note taking application sqlitebrowser # sqlite swayimg # image viewer walker # launcher wireshark zathura # pdf viewer # spell checking aspell aspellDicts.en # english aspell dictionary aspellDicts.en-computers aspellDicts.en-science aspellDicts.fi # finnish aspell dictionary enchant # spell cherker interface hunspell hunspellDicts.en-us libvoikko # finnish spelling nuspell # spell checker # support ethtool # ethernet driver info ffmpeg libcamera # source camera stack libnotify # send notifications libwebp material-icons material-symbols mermaid-cli # diagrams wl-clipboard wttrbar # weather bar # cli-tools appimage-run attic-client # nix cache client brightnessctl cloc # count llines of code dmidecode # memory information espflash # ESP32 flasher espup # ESP32 development eza # modern file list fastfetch # system information fd # find files by filenames file # show the type of file font-awesome # icons gat # cat but with extra features grim # screen capture inxi # system innformation jq # commandline json parser kramdown-asciidoc # command to convert markdown to asciidoc minio-client moor # less replacement ntfy-sh # notifications nvimpager # use neovim as pager pistol # file preview pkg-config # needed for compilation pkgs-unstable.goose-cli # llm cli pkgs-unstable.vale # spellcheck pkgs-unstable.valeStyles.microsoft # spellcheck linters pkgs-unstable.valeStyles.write-good # spellcheck linters playerctl poppler-utils # pdf utilities rdrview # extract content from web page reader # extract web page and pipe ripgrep # faster grep slurp # screen are capture sqlite # simple database timg # show image in shell whisper-cpp # tts wlogout # logout helper xdg-utils xh # curl replacement xxd # view binary files zellij # terminal multiplexer # Development antora # documentation tool for asciidoc asciidoctor-with-extensions # asciidoc is a markdown replacement clang # c and rust cmake # c couchbase-shell # couchbase d2 # graphs gnumake # makefile lean4 # theorem prover - broken lld # c and rust linker nodePackages.jsdoc # javascript documentation pkgs-unstable.go pkgs-unstable.golint # linter for go uv # python package installer ]; }; fonts = { fontconfig = { enable = true; defaultFonts = { serif = [ "Roboto Serif" ]; sansSerif = [ "Roboto Flex" ]; monospace = [ "Iosevka Nerd Font" ]; emoji = [ "Twitter Color Emoji" ]; }; }; }; xdg = { enable = true; autostart.enable = true; portal = { enable = true; xdgOpenUsePortal = true; config.common = { default = [ "*" ]; "org.freedesktop.impl.portal.FileChooser" = "termfilechooser"; }; extraPortals = with pkgs; [ xdg-desktop-portal-wlr xdg-desktop-portal-termfilechooser ]; }; desktopEntries = { nvim = { name = "nvim"; genericName = "Editor"; exec = ''${pkgs.neovim}/bin/nvim''; terminal = true; categories = [ ]; comment = "A text editor"; }; }; mimeApps = { enable = true; defaultApplications = { "application/pdf" = [ "org.pwmt.zathura.desktop" ]; "inode/directory" = "yazi.desktop"; "image/jpeg" = [ "swayimg.desktop" ]; "image/png" = [ "swayimg.desktop" ]; "image/webp" = [ "swayimg.desktop" ]; "text/html" = [ "firefox.desktop" ]; "text/json" = [ "nvim.desktop" ]; "text/markdown" = "nvim.desktop"; "text/plain" = "nvim.desktop"; "video/mp4" = "mpv.desktop"; "video/webm" = "mpv.desktop"; "x-scheme-handler/about" = "firefox.desktop"; "x-scheme-handler/http" = "firefox.desktop"; "x-scheme-handler/https" = "firefox.desktop"; "x-scheme-handler/unknown" = "firefox.desktop"; }; }; }; wayland.windowManager.hyprland.systemd.variables = [ "--all" ]; systemd.user = { startServices = "sd-switch"; }; xdg.configFile."nom/config.yml".text = '' autoread: true ordering: desc showread: false openers: - regex: "youtube" cmd: "mpv %s" - regex: ".*" cmd: "${pkgs.firefox}/bin/firefox %s" refreshinterval: 5 filtering: defaultIncludeFeedName: true backends: miniflux: host: https://flux.tammi.cc api_key: $(${pkgs.coreutils}/bin/cat ${config.age.secrets.miniflux_api_key.path}) ''; systemd.user.services.ntfy-client = { Unit = { Description = "ntfy client subscriber"; After = [ "graphical.target" ]; }; Install = { WantedBy = [ "default.target" ]; }; Service = { ExecStart = "${pkgs.ntfy-sh}/bin/ntfy subscribe --config /home/petri/.config/ntfy/client.yml --from-config"; Restart = "on-failure"; RestartSec = "10s"; ProtectSystem = "strict"; ProtectHome = "read-only"; PrivateTmp = true; NoNewPrivileges = true; RestrictRealtime = true; LockPersonality = true; }; }; xdg.configFile."xdg-desktop-portal-termfilechooser/config".text = let launcherDeps = pkgs.buildEnv { name = "yazi-launcher-dependencies"; paths = with pkgs; [ coreutils yazi gnused bashInteractive ]; }; in '' [filechooser] env=PATH='${launcherDeps}/bin' env=TERMCMD='${pkgs.ghostty}/bin/ghostty' cmd='${pkgs.xdg-desktop-portal-termfilechooser}/share/xdg-desktop-portal-termfilechooser/yazi-wrapper.sh' default_dir=$HOME/Downloads ''; systemd.user.services.bt-notify = { Unit = { Description = "Bluetooth Connection & Battery Notifications"; After = [ "graphical-session.target" ]; ConditionPathExists = "${config.home.homeDirectory}/.local/bin/bt-notify.sh"; }; Install = { WantedBy = [ "graphical-session.target" ]; }; Service = { Type = "simple"; ExecStart = "${config.home.homeDirectory}/.local/bin/bt-notify.sh"; Restart = "always"; RestartSec = 5; }; }; home.file."/.local/bin/bt-notify.sh" = { executable = true; text = '' #!/usr/bin/env bash set -euo pipefail # Temporary file to remember which devices were connected last loop STATE_FILE="/tmp/bt-connected-state" # Ensure the file exists touch "$STATE_FILE" # Listen to BlueZ D-Bus signals AND poll for battery (some devices only report on poll) ( # D-Bus listener (connection events) ${pkgs.dbus}/bin/dbus-monitor "interface=org.bluez.Device1,member=PropertiesChanged" --system & # Polling loop for battery (runs in background) while true; do ${pkgs.bluez}/bin/bluetoothctl devices | cut -f2 -d' ' | while read -r mac; do info=$(${pkgs.bluez}/bin/bluetoothctl info "$mac") name=$(echo "$info" | grep -i "Alias" | cut -d' ' -f2-) connected=$(echo "$info" | grep -i "Connected" | awk '{print $2}') battery_line=$(echo "$info" | grep -i "Battery Percentage" || true) battery=$(echo "$battery_line" | awk '{print $3}' | tr -d '()') # --- Connection change detection --- if [[ "$connected" == "yes" ]] && ! grep -q "^$mac$" "$STATE_FILE"; then ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Connected" "$name" echo "$mac" >> "$STATE_FILE" elif [[ "$connected" == "no" ]] && grep -q "^$mac$" "$STATE_FILE"; then ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Disconnected" "$name" sed -i "/^$mac$/d" "$STATE_FILE" fi # --- Low battery warning --- if [[ -n "$battery" && "$battery" -lt 20 ]]; then ${pkgs.libnotify}/bin/notify-send -u critical -a "Bluetooth" "Low Battery" "$name: ''${battery}%" fi done sleep 10 done & ) | while read -r line; do # Parse D-Bus PropertiesChanged for Connected if echo "$line" | grep -q '"Connected"'; then path=$(echo "$line" | grep -oP 'path="\K[^"]+') mac=$(basename "$path") info=$(${pkgs.bluez}/bin/bluetoothctl info "$mac") name=$(echo "$info" | grep -i "Alias" | cut -d' ' -f2-) connected=$(echo "$info" | grep -i "Connected" | awk '{print $2}') if [[ "$connected" == "yes" ]] && ! grep -q "^$mac$" "$STATE_FILE"; then ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Connected" "$name" echo "$mac" >> "$STATE_FILE" elif [[ "$connected" == "no" ]] && grep -q "^$mac$" "$STATE_FILE"; then ${pkgs.libnotify}/bin/notify-send -a "Bluetooth" "Disconnected" "$name" sed -i "/^$mac$/d" "$STATE_FILE" fi fi done ''; }; xdg.configFile."goose/config.yaml".text = '' OPENAI_BASE_PATH: v1/chat/completions extensions: developer: available_tools: [] bundled: true description: null display_name: Developer enabled: true name: developer timeout: 300 type: builtin computercontroller: bundled: true display_name: Computer Controller enabled: true name: computercontroller timeout: 300 type: builtin memory: available_tools: [] bundled: true description: Tools to save and retrieve durable memories display_name: Memory enabled: true name: memory timeout: 80 type: builtin todo: available_tools: [] bundled: true description: Enable a todo list for Goose so it can keep track of what it is doing enabled: true name: todo type: platform chatrecall: available_tools: [] bundled: true description: Search past conversations and load session summaries for contextual memory enabled: true name: chatrecall type: platform extensionmanager: available_tools: [] bundled: true description: Enable extension management tools for discovering, enabling, and disabling extensions enabled: true name: Extension Manager type: platform autovisualiser: available_tools: [] bundled: true description: Data visualisation and UI generation tools display_name: Auto Visualiser enabled: true name: autovisualiser timeout: 300 type: builtin GOOSE_MODE: auto GOOSE_PROVIDER: openai GOOSE_MODEL: gpt-4.1-mini OPENAI_HOST: https://api.openai.com ''; xdg.configFile."ntfy/client.yml".text = '' default-host: https://ntfy.tammi.cc subscribe: - topic: 77WxlkfsTzGrbYFw host: https://ntfy.tammi.cc since: 1h # (optional) only get messages from the last hour persist: true keepalive: 45s # (optional) keepalive interval format: markdown # (optional) output formatting: text, json, markdown, etc. ''; }