From 1dc4ed5f1a59216afc331075068fc630cd343e6d Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Mon, 30 Mar 2026 21:13:10 -0400 Subject: [PATCH 1/6] phase-1 --- home/bat.nix | 7 +- home/claude.nix | 13 ++-- home/common.nix | 7 ++ home/default.nix | 23 +++++-- home/ghostty.nix | 7 +- home/git.nix | 34 +++++++++- home/lazygit.nix | 4 +- home/scripts.nix | 3 +- home/security.nix | 26 +++++++ home/xdg.nix | 93 ++++++++++++++++++++++++++ home/zsh.nix | 89 ++++++------------------ hosts/netty/configuration.nix | 45 +++++++++++-- hosts/netty/hardware-configuration.nix | 1 - lib/hosts.nix | 29 +++++++- lib/package-sets.nix | 2 +- lib/theme.nix | 64 ++++++++++++++++++ modules/base.nix | 2 +- modules/hosts/netty.nix | 9 --- modules/nixpkgs.nix | 3 +- nix-maxxing.txt | 0 20 files changed, 349 insertions(+), 112 deletions(-) create mode 100644 home/security.nix create mode 100644 home/xdg.nix create mode 100644 nix-maxxing.txt diff --git a/home/bat.nix b/home/bat.nix index 967652f..50f1b76 100644 --- a/home/bat.nix +++ b/home/bat.nix @@ -1,10 +1,13 @@ -{ ... }: +{ config, ... }: +let + theme = import ../lib/theme.nix { inherit config; }; +in { programs.bat = { enable = true; config = { - theme = "gruvbox-dark"; + theme = theme.batTheme theme.defaultMode; }; }; } diff --git a/home/claude.nix b/home/claude.nix index 3a1b188..bf023fb 100644 --- a/home/claude.nix +++ b/home/claude.nix @@ -7,17 +7,16 @@ let claudePackage = inputs.claudeCode.packages.${pkgs.stdenv.hostPlatform.system}.default; in { - # Keep the managed Claude binary on the same path the live machine was using - # so the Nix package cleanly replaces the prior manual install. home.file.".local/bin/claude".source = "${claudePackage}/bin/claude"; - home.file.".claude/CLAUDE.md".source = ../config/claude/CLAUDE.md; - home.file.".claude/commands" = { + + xdg.configFile."claude/CLAUDE.md".source = ../config/claude/CLAUDE.md; + xdg.configFile."claude/commands" = { source = ../config/claude/commands; recursive = true; }; - home.file.".claude/settings.json".source = ../config/claude/settings.json; - home.file.".claude/settings.local.json".source = ../config/claude/settings.local.json; - home.file.".claude/statusline.sh" = { + xdg.configFile."claude/settings.json".source = ../config/claude/settings.json; + xdg.configFile."claude/settings.local.json".source = ../config/claude/settings.local.json; + xdg.configFile."claude/statusline.sh" = { source = ../config/claude/statusline.sh; executable = true; }; diff --git a/home/common.nix b/home/common.nix index 35fa271..9008cb4 100644 --- a/home/common.nix +++ b/home/common.nix @@ -4,6 +4,8 @@ ./bat.nix ./eza.nix ./claude.nix + ./xdg.nix + ./security.nix ./codex.nix ./fzf.nix ./gcloud.nix @@ -25,4 +27,9 @@ home.stateVersion = "24.11"; programs.home-manager.enable = true; xdg.enable = true; + + programs.zoxide = { + enable = true; + enableZshIntegration = true; + }; } diff --git a/home/default.nix b/home/default.nix index 22c67d0..ccd1fd7 100644 --- a/home/default.nix +++ b/home/default.nix @@ -1,8 +1,19 @@ -{ ... }: { - imports = [ - ./common.nix - ./colima.nix - ./rectangle.nix - ]; + lib, + hostConfig, + ... +}: +{ + imports = + [ + ./common.nix + ] + ++ lib.optionals hostConfig.isDarwin [ + ./colima.nix + ./rectangle.nix + ./karabiner.nix + ] + ++ lib.optionals hostConfig.isLinux [ + ./netty-worktree.nix + ]; } diff --git a/home/ghostty.nix b/home/ghostty.nix index c660cf9..dd768df 100644 --- a/home/ghostty.nix +++ b/home/ghostty.nix @@ -2,6 +2,7 @@ config, lib, pkgs, + hostConfig, ... }: let @@ -40,7 +41,7 @@ let keybind = vim/i=deactivate_key_table keybind = vim/catch_all=ignore mouse-hide-while-typing = true - ${lib.optionalString pkgs.stdenv.isDarwin '' + ${lib.optionalString hostConfig.isDarwin '' macos-titlebar-style = hidden macos-option-as-alt = true ''} @@ -57,7 +58,7 @@ in { programs.ghostty = { enable = true; - package = if pkgs.stdenv.isDarwin then pkgs.ghostty-bin else pkgs.ghostty; + package = if hostConfig.isDarwin then pkgs.ghostty-bin else pkgs.ghostty; installBatSyntax = true; }; @@ -69,7 +70,7 @@ in xdg.configFile."ghostty/themes/cozybox-dark".text = theme.renderGhostty "dark"; xdg.configFile."ghostty/themes/cozybox-light".text = theme.renderGhostty "light"; - home.file = lib.mkIf pkgs.stdenv.isDarwin { + home.file = lib.mkIf hostConfig.isDarwin { "Library/Application Support/com.mitchellh.ghostty/config.ghostty" = { text = ghosttyConfig; force = true; diff --git a/home/git.nix b/home/git.nix index 7e2bb02..8ef05d2 100644 --- a/home/git.nix +++ b/home/git.nix @@ -1,10 +1,40 @@ -{ ... }: +{ config, ... }: +let + theme = import ../lib/theme.nix { inherit config; }; +in { programs.git = { enable = true; lfs.enable = true; signing.format = "openpgp"; + ignores = [ + "*.swp" + "*.swo" + "*~" + ".DS_Store" + "Thumbs.db" + ".env" + ".env.local" + ".env.*.local" + ".vscode/" + ".idea/" + ".claude/" + "CLAUDE.md" + "node_modules/" + "__pycache__/" + "*.pyc" + "venv/" + ".venv/" + "build/" + "dist/" + "out/" + "target/" + "result" + "result-*" + ".direnv/" + ]; + settings = { user = { name = "Harivansh Rathi"; @@ -40,7 +70,7 @@ }; delta = { - "syntax-theme" = "gruvbox-dark"; + "syntax-theme" = theme.deltaTheme theme.defaultMode; "hunk-header-style" = "omit"; "minus-style" = ''syntax "#3c1f1e"''; "minus-emph-style" = ''syntax "#72261d"''; diff --git a/home/lazygit.nix b/home/lazygit.nix index 3297091..e9459ef 100644 --- a/home/lazygit.nix +++ b/home/lazygit.nix @@ -1,12 +1,12 @@ { lib, - pkgs, + hostConfig, ... }: { xdg.configFile."lazygit/config.yml".source = ../config/lazygit/config.yml; - home.file = lib.mkIf pkgs.stdenv.isDarwin { + home.file = lib.mkIf hostConfig.isDarwin { "Library/Application Support/lazygit/config.yml".source = ../config/lazygit/config.yml; }; } diff --git a/home/scripts.nix b/home/scripts.nix index a3a8f94..670db99 100644 --- a/home/scripts.nix +++ b/home/scripts.nix @@ -2,6 +2,7 @@ config, lib, pkgs, + hostConfig, ... }: let @@ -10,7 +11,7 @@ in { home.packages = builtins.attrValues customScripts.commonPackages - ++ lib.optionals pkgs.stdenv.isDarwin (builtins.attrValues customScripts.darwinPackages); + ++ lib.optionals hostConfig.isDarwin (builtins.attrValues customScripts.darwinPackages); home.activation.initializeThemeState = lib.hm.dag.entryAfter [ "writeBoundary" ] '' mkdir -p "${customScripts.theme.paths.stateDir}" "${customScripts.theme.paths.fzfDir}" "${customScripts.theme.paths.ghosttyDir}" "${customScripts.theme.paths.tmuxDir}" diff --git a/home/security.nix b/home/security.nix new file mode 100644 index 0000000..8d1a4ed --- /dev/null +++ b/home/security.nix @@ -0,0 +1,26 @@ +{ + config, + lib, + ... +}: +{ + home.activation.secretPermissions = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + if [ -d "${config.home.homeDirectory}/.ssh" ]; then + $DRY_RUN_CMD chmod 700 "${config.home.homeDirectory}/.ssh" + for f in "${config.home.homeDirectory}/.ssh/"*; do + [ -f "$f" ] || continue + [ -L "$f" ] && continue + case "$f" in + *.pub|*/known_hosts|*/known_hosts.old) + $DRY_RUN_CMD chmod 644 "$f" ;; + *) + $DRY_RUN_CMD chmod 600 "$f" ;; + esac + done + fi + if [ -d "${config.home.homeDirectory}/.gnupg" ]; then + $DRY_RUN_CMD find "${config.home.homeDirectory}/.gnupg" -type d -exec chmod 700 {} + + $DRY_RUN_CMD find "${config.home.homeDirectory}/.gnupg" -type f -exec chmod 600 {} + + fi + ''; +} diff --git a/home/xdg.nix b/home/xdg.nix new file mode 100644 index 0000000..064ee57 --- /dev/null +++ b/home/xdg.nix @@ -0,0 +1,93 @@ +{ + config, + lib, + hostConfig, + ... +}: +let + f = hostConfig.features; +in +{ + home.sessionVariables = lib.mkMerge [ + { + LESSHISTFILE = "-"; + WGETRC = "${config.xdg.configHome}/wgetrc"; + } + (lib.mkIf (f.rust or false) { + CARGO_HOME = "${config.xdg.dataHome}/cargo"; + RUSTUP_HOME = "${config.xdg.dataHome}/rustup"; + }) + (lib.mkIf (f.go or false) { + GOPATH = "${config.xdg.dataHome}/go"; + GOMODCACHE = "${config.xdg.cacheHome}/go/mod"; + }) + (lib.mkIf (f.node or false) { + NPM_CONFIG_USERCONFIG = "${config.xdg.configHome}/npm/npmrc"; + NODE_REPL_HISTORY = "${config.xdg.stateHome}/node_repl_history"; + PNPM_HOME = "${config.xdg.dataHome}/pnpm"; + PNPM_NO_UPDATE_NOTIFIER = "true"; + }) + (lib.mkIf (f.python or false) { + PYTHONSTARTUP = "${config.xdg.configHome}/python/pythonrc"; + PYTHON_HISTORY = "${config.xdg.stateHome}/python_history"; + PYTHONPYCACHEPREFIX = "${config.xdg.cacheHome}/python"; + PYTHONUSERBASE = "${config.xdg.dataHome}/python"; + }) + (lib.mkIf (f.docker or false) { + DOCKER_CONFIG = "${config.xdg.configHome}/docker"; + }) + (lib.mkIf (f.aws or false) { + AWS_SHARED_CREDENTIALS_FILE = "${config.xdg.configHome}/aws/credentials"; + AWS_CONFIG_FILE = "${config.xdg.configHome}/aws/config"; + }) + (lib.mkIf (f.claude or false) { + CLAUDE_CONFIG_DIR = "${config.xdg.configHome}/claude"; + }) + { + PSQL_HISTORY = "${config.xdg.stateHome}/psql_history"; + SQLITE_HISTORY = "${config.xdg.stateHome}/sqlite_history"; + } + ]; + + home.sessionPath = lib.mkMerge [ + [ "${config.home.homeDirectory}/.local/bin" ] + (lib.mkIf (f.rust or false) [ "${config.xdg.dataHome}/cargo/bin" ]) + (lib.mkIf (f.go or false) [ "${config.xdg.dataHome}/go/bin" ]) + (lib.mkIf (f.node or false) [ "${config.xdg.dataHome}/pnpm" ]) + ]; + + xdg.configFile."npm/npmrc" = lib.mkIf (f.node or false) { + text = '' + prefix=''${XDG_DATA_HOME}/npm + cache=''${XDG_CACHE_HOME}/npm + init-module=''${XDG_CONFIG_HOME}/npm/config/npm-init.js + ''; + }; + + xdg.configFile."python/pythonrc" = lib.mkIf (f.python or false) { + text = '' + import atexit + import os + import readline + + history = os.path.join(os.environ.get('XDG_STATE_HOME', os.path.expanduser('~/.local/state')), 'python_history') + + try: + readline.read_history_file(history) + except OSError: + pass + + def write_history(): + try: + readline.write_history_file(history) + except OSError: + pass + + atexit.register(write_history) + ''; + }; + + xdg.configFile."wgetrc".text = '' + hsts_file = ${config.xdg.stateHome}/wget-hsts + ''; +} diff --git a/home/zsh.nix b/home/zsh.nix index 0c23065..dbc99c4 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -2,8 +2,12 @@ config, lib, pkgs, + hostConfig, ... }: +let + theme = import ../lib/theme.nix { inherit config; }; +in { home.file.".oh-my-zsh/custom/themes/agnoster.zsh-theme".source = ../config/agnoster.zsh-theme; @@ -22,6 +26,17 @@ autosuggestion.enable = true; syntaxHighlighting.enable = true; + history = { + size = 50000; + save = 50000; + ignoreDups = true; + ignoreAllDups = true; + ignoreSpace = true; + extended = true; + append = true; + path = "${config.xdg.stateHome}/zsh_history"; + }; + shellAliases = { co = "codex --dangerously-bypass-approvals-and-sandbox"; ca = "cursor-agent"; @@ -38,7 +53,7 @@ lg = "lazygit"; nim = "nvim ."; } - // lib.optionalAttrs pkgs.stdenv.isDarwin { + // lib.optionalAttrs hostConfig.isDarwin { tailscale = "/Applications/Tailscale.app/Contents/MacOS/Tailscale"; }; @@ -48,7 +63,7 @@ fi export NODE_NO_WARNINGS=1 '' - + lib.optionalString pkgs.stdenv.isDarwin '' + + lib.optionalString hostConfig.isDarwin '' # Ghostty shell integration expects a resource directory; the Nix app # bundle lives in the store instead of /Applications. export GHOSTTY_RESOURCES_DIR="${pkgs.ghostty-bin}/Applications/Ghostty.app/Contents/Resources/ghostty" @@ -80,29 +95,21 @@ source ~/.secrets fi - eval "$(zoxide init zsh)" - [ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun" export BUN_INSTALL="$HOME/.bun" - export PNPM_HOME="${ - if pkgs.stdenv.isDarwin then "$HOME/Library/pnpm" else "${config.xdg.dataHome}/pnpm" - }" - bindkey -v typeset -U path PATH path=( "$HOME/.amp/bin" - "$PNPM_HOME" "$BUN_INSTALL/bin" "$HOME/.antigravity/antigravity/bin" "$HOME/.opencode/bin" "${pkgs.postgresql_17}/bin" - "$HOME/.local/bin" "$HOME/.nix-profile/bin" "/etc/profiles/per-user/${config.home.username}/bin" "/run/current-system/sw/bin" "/nix/var/nix/profiles/default/bin" - ${lib.optionalString pkgs.stdenv.isDarwin '' + ${lib.optionalString hostConfig.isDarwin '' "/opt/homebrew/bin" "/opt/homebrew/sbin" ''} @@ -132,63 +139,9 @@ typeset -gA ZSH_HIGHLIGHT_STYLES if [[ "$mode" == light ]]; then - ZSH_HIGHLIGHT_STYLES[arg0]='fg=#427b58' - ZSH_HIGHLIGHT_STYLES[autodirectory]='fg=#427b58,underline' - ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[back-quoted-argument-delimiter]='fg=#8f3f71' - ZSH_HIGHLIGHT_STYLES[bracket-error]='fg=#ea6962,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=#076678,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=#427b58,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=#8f3f71,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=#b57614,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=#076678,bold' - ZSH_HIGHLIGHT_STYLES[comment]='fg=#928374' - ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]='fg=#8f3f71' - ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=#b57614' - ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=#b57614' - ZSH_HIGHLIGHT_STYLES[global-alias]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[globbing]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[path]='fg=#3c3836,underline' - ZSH_HIGHLIGHT_STYLES[precommand]='fg=#427b58,underline' - ZSH_HIGHLIGHT_STYLES[process-substitution-delimiter]='fg=#8f3f71' - ZSH_HIGHLIGHT_STYLES[rc-quote]='fg=#076678' - ZSH_HIGHLIGHT_STYLES[redirection]='fg=#b57614' - ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#b57614' - ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=#b57614' - ZSH_HIGHLIGHT_STYLES[suffix-alias]='fg=#427b58,underline' - ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#ea6962,bold' + ${theme.renderZshHighlights "light"} else - ZSH_HIGHLIGHT_STYLES[arg0]='fg=#8ec97c' - ZSH_HIGHLIGHT_STYLES[autodirectory]='fg=#8ec97c,underline' - ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]='fg=#8ec07c' - ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]='fg=#8ec07c' - ZSH_HIGHLIGHT_STYLES[back-quoted-argument-delimiter]='fg=#d3869b' - ZSH_HIGHLIGHT_STYLES[bracket-error]='fg=#ea6962,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=#5b84de,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=#8ec97c,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=#d3869b,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=#d8a657,bold' - ZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=#8ec07c,bold' - ZSH_HIGHLIGHT_STYLES[comment]='fg=#7c6f64' - ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]='fg=#d3869b' - ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=#8ec07c' - ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=#d8a657' - ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=#d8a657' - ZSH_HIGHLIGHT_STYLES[global-alias]='fg=#8ec07c' - ZSH_HIGHLIGHT_STYLES[globbing]='fg=#5b84de' - ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#5b84de' - ZSH_HIGHLIGHT_STYLES[path]='fg=#d4be98,underline' - ZSH_HIGHLIGHT_STYLES[precommand]='fg=#8ec97c,underline' - ZSH_HIGHLIGHT_STYLES[process-substitution-delimiter]='fg=#d3869b' - ZSH_HIGHLIGHT_STYLES[rc-quote]='fg=#8ec07c' - ZSH_HIGHLIGHT_STYLES[redirection]='fg=#d8a657' - ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#d8a657' - ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=#d8a657' - ZSH_HIGHLIGHT_STYLES[suffix-alias]='fg=#8ec97c,underline' - ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#ea6962,bold' + ${theme.renderZshHighlights "dark"} fi typeset -g _CODEX_LAST_HIGHLIGHT_THEME="$mode" @@ -249,7 +202,7 @@ _codex_apply_highlight_styles - ${lib.optionalString pkgs.stdenv.isDarwin '' + ${lib.optionalString hostConfig.isDarwin '' if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh)" diff --git a/hosts/netty/configuration.nix b/hosts/netty/configuration.nix index e983743..a1492c2 100644 --- a/hosts/netty/configuration.nix +++ b/hosts/netty/configuration.nix @@ -1,6 +1,7 @@ { inputs, lib, + modulesPath, pkgs, username, self, @@ -14,6 +15,8 @@ in ./hardware-configuration.nix ./disk-config.nix ../../modules/base.nix + (modulesPath + "/profiles/minimal.nix") + (modulesPath + "/profiles/headless.nix") ]; boot.loader.grub = { @@ -21,12 +24,31 @@ in efiSupport = true; efiInstallAsRemovable = true; device = "nodev"; - configurationLimit = 5; + configurationLimit = 3; }; + documentation.enable = false; + fonts.fontconfig.enable = false; + networking = { hostName = "netty"; - useDHCP = true; + useDHCP = false; + interfaces.ens3 = { + ipv4.addresses = [ + { + address = "152.53.195.59"; + prefixLength = 22; + } + ]; + }; + defaultGateway = { + address = "152.53.192.1"; + interface = "ens3"; + }; + nameservers = [ + "1.1.1.1" + "8.8.8.8" + ]; firewall.allowedTCPPorts = [ 22 80 @@ -44,9 +66,13 @@ in }; }; - users.users.root.openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM6tzq33IQcurWoQ7vhXOTLjv8YkdTGb7NoNsul3Sbfu rathi@mac" - ]; + # Emergency console access - generate hashed password and save to Bitwarden later + users.users.root = { + initialPassword = "temppass123"; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM6tzq33IQcurWoQ7vhXOTLjv8YkdTGb7NoNsul3Sbfu rathi@mac" + ]; + }; users.users.${username} = { isNormalUser = true; @@ -64,6 +90,15 @@ in username ]; + nix.gc.options = lib.mkForce "--delete-older-than 3d"; + + nix.extraOptions = '' + min-free = ${toString (100 * 1024 * 1024)} + max-free = ${toString (1024 * 1024 * 1024)} + ''; + + services.journald.extraConfig = "MaxRetainedFileSec=1week"; + environment.systemPackages = packageSets.extras ++ [ pkgs.bubblewrap pkgs.pnpm diff --git a/hosts/netty/hardware-configuration.nix b/hosts/netty/hardware-configuration.nix index 47bbb8c..a449326 100644 --- a/hosts/netty/hardware-configuration.nix +++ b/hosts/netty/hardware-configuration.nix @@ -22,6 +22,5 @@ virtualisation.hypervGuest.enable = false; - networking.useDHCP = lib.mkDefault true; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; } diff --git a/lib/hosts.nix b/lib/hosts.nix index 2aaef04..7971995 100644 --- a/lib/hosts.nix +++ b/lib/hosts.nix @@ -5,8 +5,20 @@ kind = "darwin"; system = "aarch64-darwin"; hostname = "hari-macbook-pro"; - homeModule = ../home; homeDirectory = "/Users/${username}"; + isDarwin = true; + isLinux = false; + isNixOS = false; + features = { + rust = true; + go = true; + node = true; + python = true; + aws = true; + claude = true; + docker = true; + tex = true; + }; }; netty = { @@ -14,8 +26,19 @@ kind = "nixos"; system = "x86_64-linux"; hostname = "netty"; - homeModule = ../home/netty.nix; - standaloneHomeModule = ../hosts/netty; homeDirectory = "/home/${username}"; + isDarwin = false; + isLinux = true; + isNixOS = true; + features = { + rust = true; + go = true; + node = true; + python = true; + aws = true; + claude = true; + docker = false; + tex = false; + }; }; } diff --git a/lib/package-sets.nix b/lib/package-sets.nix index 40d69e2..5228e15 100644 --- a/lib/package-sets.nix +++ b/lib/package-sets.nix @@ -104,11 +104,11 @@ in redis tailscale terraform - texliveFull yt-dlp ]) ++ lib.optionals pkgs.stdenv.isDarwin [ agentcomputerPackage + texliveFull ] ++ [ openspecPackage diff --git a/lib/theme.nix b/lib/theme.nix index b4c2c8d..f118017 100644 --- a/lib/theme.nix +++ b/lib/theme.nix @@ -140,14 +140,78 @@ let --color=fg+:${theme.text},bg+:${theme.surface},hl+:${theme.blue} --color=info:${theme.green},prompt:${theme.blue},pointer:${theme.text},marker:${theme.green},spinner:${theme.text} ''; + batTheme = mode: if mode == "light" then "gruvbox-light" else "gruvbox-dark"; + + deltaTheme = mode: if mode == "light" then "gruvbox-light" else "gruvbox-dark"; + + renderZshHighlights = + mode: + let + # Light mode uses gruvbox-light specific colors + light = { + arg0 = "#427b58"; + aqua = "#076678"; + purple = "#8f3f71"; + yellow = "#b57614"; + text = "#3c3836"; + comment = "#928374"; + error = "#ea6962"; + }; + # Dark mode uses our theme palette + dark = { + arg0 = sharedPalette.green; + aqua = sharedPalette.aqua; + purple = sharedPalette.purple; + yellow = "#d8a657"; + text = "#d4be98"; + comment = "#7c6f64"; + error = sharedPalette.red; + blue = sharedPalette.blue; + }; + c = if mode == "light" then light else dark; + blueOrAqua = if mode == "light" then c.aqua else c.blue; + in + '' + ZSH_HIGHLIGHT_STYLES[arg0]='fg=${c.arg0}' + ZSH_HIGHLIGHT_STYLES[autodirectory]='fg=${c.arg0},underline' + ZSH_HIGHLIGHT_STYLES[back-dollar-quoted-argument]='fg=${if mode == "light" then c.aqua else c.aqua}' + ZSH_HIGHLIGHT_STYLES[back-double-quoted-argument]='fg=${if mode == "light" then c.aqua else c.aqua}' + ZSH_HIGHLIGHT_STYLES[back-quoted-argument-delimiter]='fg=${c.purple}' + ZSH_HIGHLIGHT_STYLES[bracket-error]='fg=${c.error},bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-1]='fg=${blueOrAqua},bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-2]='fg=${c.arg0},bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-3]='fg=${c.purple},bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-4]='fg=${c.yellow},bold' + ZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=${if mode == "light" then c.aqua else c.aqua},bold' + ZSH_HIGHLIGHT_STYLES[comment]='fg=${c.comment}' + ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]='fg=${c.purple}' + ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=${if mode == "light" then c.aqua else c.aqua}' + ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=${c.yellow}' + ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=${c.yellow}' + ZSH_HIGHLIGHT_STYLES[global-alias]='fg=${if mode == "light" then c.aqua else c.aqua}' + ZSH_HIGHLIGHT_STYLES[globbing]='fg=${blueOrAqua}' + ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=${blueOrAqua}' + ZSH_HIGHLIGHT_STYLES[path]='fg=${c.text},underline' + ZSH_HIGHLIGHT_STYLES[precommand]='fg=${c.arg0},underline' + ZSH_HIGHLIGHT_STYLES[process-substitution-delimiter]='fg=${c.purple}' + ZSH_HIGHLIGHT_STYLES[rc-quote]='fg=${if mode == "light" then c.aqua else c.aqua}' + ZSH_HIGHLIGHT_STYLES[redirection]='fg=${c.yellow}' + ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=${c.yellow}' + ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=${c.yellow}' + ZSH_HIGHLIGHT_STYLES[suffix-alias]='fg=${c.arg0},underline' + ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=${c.error},bold' + ''; in { inherit + batTheme defaultMode + deltaTheme paths renderFzf renderGhostty renderTmux + renderZshHighlights themes ; } diff --git a/modules/base.nix b/modules/base.nix index 0eab198..6e22765 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -26,7 +26,7 @@ in nix.gc = { automatic = true; - options = "--delete-older-than 14d"; + options = lib.mkDefault "--delete-older-than 14d"; } // ( if pkgs.stdenv.isDarwin then diff --git a/modules/hosts/netty.nix b/modules/hosts/netty.nix index a5d090e..850d7c3 100644 --- a/modules/hosts/netty.nix +++ b/modules/hosts/netty.nix @@ -1,7 +1,6 @@ { hosts, inputs, - mkPkgs, mkSpecialArgs, mkHomeManagerModule, ... @@ -21,13 +20,5 @@ in (mkHomeManagerModule host) ]; }; - - homeConfigurations.${host.name} = inputs.home-manager.lib.homeManagerConfiguration { - pkgs = mkPkgs host.system; - extraSpecialArgs = mkSpecialArgs host; - modules = [ - host.standaloneHomeModule - ]; - }; }; } diff --git a/modules/nixpkgs.nix b/modules/nixpkgs.nix index 32212fa..7a48be6 100644 --- a/modules/nixpkgs.nix +++ b/modules/nixpkgs.nix @@ -18,6 +18,7 @@ let mkSpecialArgs = host: { inherit inputs self username; hostname = host.hostname; + hostConfig = host; }; mkHomeManagerModule = host: { @@ -25,7 +26,7 @@ let home-manager.useUserPackages = true; home-manager.extraSpecialArgs = mkSpecialArgs host; home-manager.backupCommand = "bash ${../scripts/home-manager-backup.sh}"; - home-manager.users.${username} = import host.homeModule; + home-manager.users.${username} = import ../home; }; in { diff --git a/nix-maxxing.txt b/nix-maxxing.txt new file mode 100644 index 0000000..e69de29 From 9cfe51145d7f17190cd07810868743c453d47f10 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Mon, 30 Mar 2026 21:44:55 -0400 Subject: [PATCH 2/6] finish --- README.md | 26 ++++-- hosts/netty/configuration.nix | 154 ++++++++++++++++++++++++++++++ nix-maxxing.txt | 171 ++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 70b6a25..91f47cf 100644 --- a/README.md +++ b/README.md @@ -49,14 +49,20 @@ just fmt ## layout ``` -hosts/darwin/ - macOS host entrypoint -hosts/netty/ - NixOS VPS entrypoint (disko + hardware) -modules/ - shared system modules + devshells -modules/hosts/ - flake-parts host output definitions -modules/nixpkgs.nix - shared flake context (hosts, args, pkgs helpers) -home/ - Home Manager modules -lib/hosts.nix - host metadata used by the flake -lib/ - shared package sets and theme system -config/ - repo-owned config files (nvim, tmux, etc.) -scripts/ - secret management and utility scripts +hosts/darwin/ - macOS host entrypoint +hosts/netty/ - NixOS VPS entrypoint (disko + hardware + services) +modules/ - shared system modules + devshells +modules/hosts/ - flake-parts host output definitions +modules/nixpkgs.nix - shared flake context (hosts, specialArgs, pkgs) +home/default.nix - unified home entry (conditional on hostConfig) +home/common.nix - modules shared across all hosts +home/xdg.nix - XDG compliance (env vars, config files) +home/security.nix - SSH/GPG permission enforcement +home/ - per-tool home-manager modules +lib/hosts.nix - host metadata + feature flags +lib/theme.nix - centralized color system (gruvbox) +lib/package-sets.nix - shared + host-gated package lists +config/ - repo-owned config files (nvim, tmux, etc.) +scripts/ - secret management and utility scripts +nix-maxxing.txt - architecture and operations guide ``` diff --git a/hosts/netty/configuration.nix b/hosts/netty/configuration.nix index a1492c2..ec08f18 100644 --- a/hosts/netty/configuration.nix +++ b/hosts/netty/configuration.nix @@ -102,12 +102,166 @@ in environment.systemPackages = packageSets.extras ++ [ pkgs.bubblewrap pkgs.pnpm + pkgs.nodejs ]; systemd.tmpfiles.rules = [ "L /usr/bin/bwrap - - - - ${pkgs.bubblewrap}/bin/bwrap" ]; + # --- ACME / Let's Encrypt --- + security.acme = { + acceptTerms = true; + defaults.email = "rathiharivansh@gmail.com"; + }; + + # --- Nginx reverse proxy --- + services.nginx = { + enable = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + clientMaxBodySize = "512m"; + + virtualHosts."sandbox.example.dev" = { + enableACME = true; + forceSSL = true; + locations."/".proxyPass = "http://127.0.0.1:2470"; + }; + + virtualHosts."git.example.dev" = { + enableACME = true; + forceSSL = true; + locations."/".proxyPass = "http://127.0.0.1:3000"; + }; + }; + + # --- Forgejo --- + users.users.git = { + isSystemUser = true; + home = "/var/lib/forgejo"; + group = "git"; + shell = "${pkgs.bash}/bin/bash"; + }; + users.groups.git = { }; + + services.forgejo = { + enable = true; + user = "git"; + group = "git"; + settings = { + server = { + DOMAIN = "git.example.dev"; + ROOT_URL = "https://git.example.dev/"; + HTTP_PORT = 3000; + SSH_DOMAIN = "git.example.dev"; + }; + service.DISABLE_REGISTRATION = true; + session.COOKIE_SECURE = true; + mirror = { + DEFAULT_INTERVAL = "1h"; + MIN_INTERVAL = "10m"; + }; + }; + }; + + # --- Forgejo mirror sync (hourly) --- + systemd.services.forgejo-mirror-sync = { + description = "Sync GitHub mirrors to Forgejo"; + after = [ "forgejo.service" ]; + requires = [ "forgejo.service" ]; + serviceConfig = { + Type = "oneshot"; + EnvironmentFile = "/etc/forgejo-mirror.env"; + }; + path = [ pkgs.curl pkgs.jq pkgs.coreutils ]; + script = '' + set -euo pipefail + + # Fetch all GitHub repos + page=1 + repos="" + while true; do + batch=$(curl -sf -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/user/repos?per_page=100&page=$page&affiliation=owner") + count=$(echo "$batch" | jq length) + [ "$count" -eq 0 ] && break + repos="$repos$batch" + page=$((page + 1)) + done + + echo "$repos" | jq -r '.[].clone_url' | while read -r clone_url; do + repo_name=$(basename "$clone_url" .git) + + # Check if mirror already exists in Forgejo + status=$(curl -sf -o /dev/null -w '%{http_code}' \ + -H "Authorization: token $FORGEJO_TOKEN" \ + "$FORGEJO_URL/api/v1/repos/$FORGEJO_OWNER/$repo_name") + + if [ "$status" = "404" ]; then + # Create mirror + curl -sf -X POST \ + -H "Authorization: token $FORGEJO_TOKEN" \ + -H "Content-Type: application/json" \ + "$FORGEJO_URL/api/v1/repos/migrate" \ + -d "{ + \"clone_addr\": \"$clone_url\", + \"auth_token\": \"$GITHUB_TOKEN\", + \"uid\": $(curl -sf -H "Authorization: token $FORGEJO_TOKEN" "$FORGEJO_URL/api/v1/user" | jq .id), + \"repo_name\": \"$repo_name\", + \"mirror\": true, + \"service\": \"github\" + }" + echo "Created mirror: $repo_name" + else + # Trigger sync on existing mirror + curl -sf -X POST \ + -H "Authorization: token $FORGEJO_TOKEN" \ + "$FORGEJO_URL/api/v1/repos/$FORGEJO_OWNER/$repo_name/mirror-sync" || true + echo "Synced mirror: $repo_name" + fi + done + ''; + }; + + systemd.timers.forgejo-mirror-sync = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "hourly"; + Persistent = true; + RandomizedDelaySec = "5m"; + }; + }; + + # --- Sandbox Agent (declarative systemd services) --- + systemd.services.sandbox-agent = { + description = "Sandbox Agent"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + User = username; + Group = "users"; + EnvironmentFile = "/home/${username}/.config/sandbox-agent/agent.env"; + ExecStart = "/home/${username}/.local/bin/sandbox-agent"; + Restart = "on-failure"; + RestartSec = 5; + }; + }; + + systemd.services.sandbox-cors-proxy = { + description = "Sandbox CORS Proxy"; + after = [ "sandbox-agent.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + User = username; + Group = "users"; + ExecStart = "${pkgs.nodejs}/bin/node /home/${username}/.config/sandbox-agent/cors-proxy.js"; + Restart = "on-failure"; + RestartSec = 5; + }; + }; + system.configurationRevision = self.rev or self.dirtyRev or null; system.stateVersion = "24.11"; } diff --git a/nix-maxxing.txt b/nix-maxxing.txt index e69de29..d2683ce 100644 --- a/nix-maxxing.txt +++ b/nix-maxxing.txt @@ -0,0 +1,171 @@ +Nix Config - Architecture and Operations Guide +================================================ + +1. WHY STATIC IP (NOT DHCP) +---------------------------- +DHCP on a VPS is dangerous. If the DHCP lease expires or the server +reboots while the DHCP server is unreachable, the machine loses its IP +and becomes inaccessible via SSH. This happened on netty (2026-03-30). + +Static config in hosts/netty/configuration.nix: + - IP: 152.53.195.59/22 + - Gateway: 152.53.192.1 + - Interface: ens3 + - DNS: 1.1.1.1, 8.8.8.8 + +Always verify the interface name with `ip link show` before changing +network config. Keep VNC console access available as a fallback. + + +2. HOST ABSTRACTION (hostConfig) +--------------------------------- +lib/hosts.nix defines each machine with: + - isDarwin / isLinux / isNixOS booleans + - features map (rust, go, node, python, aws, claude, docker, tex) + +modules/nixpkgs.nix passes hostConfig via specialArgs so all home-manager +modules can use it. This replaces scattered `pkgs.stdenv.isDarwin` checks. + +To add a new host: + 1. Add entry to lib/hosts.nix with all fields + 2. Create hosts//configuration.nix (NixOS) or add darwin case + 3. Add host output in modules/hosts/.nix + 4. home/default.nix auto-selects modules based on hostConfig flags + +home/default.nix is the unified entry point - no separate per-host home +modules needed. + + +3. XDG COMPLIANCE +------------------ +home/xdg.nix sets environment variables so tools respect XDG dirs: + + CARGO_HOME -> $XDG_DATA_HOME/cargo + RUSTUP_HOME -> $XDG_DATA_HOME/rustup + GOPATH -> $XDG_DATA_HOME/go + GOMODCACHE -> $XDG_CACHE_HOME/go/mod + NPM_CONFIG_USERCONFIG -> $XDG_CONFIG_HOME/npm/npmrc + NODE_REPL_HISTORY -> $XDG_STATE_HOME/node_repl_history + PYTHON_HISTORY -> $XDG_STATE_HOME/python_history + AWS_CONFIG_FILE -> $XDG_CONFIG_HOME/aws/config + DOCKER_CONFIG -> $XDG_CONFIG_HOME/docker + CLAUDE_CONFIG_DIR -> $XDG_CONFIG_HOME/claude + PSQL_HISTORY -> $XDG_STATE_HOME/psql_history + SQLITE_HISTORY -> $XDG_STATE_HOME/sqlite_history + LESSHISTFILE -> "-" (disabled) + +All gated by hostConfig.features so tools only get configured when +the feature flag is set for that host. + + +4. SECURITY MODULE +------------------- +home/security.nix runs activation scripts on every `home-manager switch`: + - ~/.ssh/ dir: 700, private keys: 600, pub/known_hosts/config: 644 + - ~/.gnupg/ dirs: 700, files: 600 + +No manual chmod needed after restoring keys from Bitwarden. + + +5. THEME SYSTEM +---------------- +lib/theme.nix is the single source of truth for colors. + +Shared palette (gruvbox-inspired) used across: + - Ghostty terminal (renderGhostty) + - Tmux status bar (renderTmux) + - fzf color scheme (renderFzf) + - Zsh syntax highlighting (renderZshHighlights) + - Bat (batTheme) + - Git delta (deltaTheme) + +Runtime toggle: `theme toggle` writes "light" or "dark" to +$XDG_STATE_HOME/theme/current, then updates Ghostty, tmux, fzf, +and Neovim (via RPC) live. Bat and delta are static at build time. + + +6. SHELL SETUP +--------------- +oh-my-zsh with agnoster theme (powerline arrows + git branch coloring). +Vim mode via defaultKeymap = "viins" with cursor shape switching +(beam for insert, block for normal). + +History: 50k entries, dedup, ignoreSpace, extended format, stored at +$XDG_STATE_HOME/zsh_history. + +zoxide: declarative via programs.zoxide (no manual eval). + +PATH: managed via home.sessionPath in xdg.nix + initContent block +in zsh.nix for entries that need conditional logic. + + +7. SERVER SERVICES (netty) +--------------------------- +All in hosts/netty/configuration.nix: + +Nginx reverse proxy with ACME SSL: + - sandbox.example.dev -> 127.0.0.1:2470 (sandbox agent) + - git.example.dev -> 127.0.0.1:3000 (forgejo) + +Forgejo: + - Self-hosted git, registration disabled + - Runs as git user on port 3000 + - GitHub mirror sync via hourly systemd timer + - Requires /etc/forgejo-mirror.env with GITHUB_TOKEN, FORGEJO_TOKEN, + FORGEJO_URL, FORGEJO_OWNER + +Sandbox Agent: + - System-level systemd services (not user units) + - sandbox-agent on :2470, env from ~/.config/sandbox-agent/agent.env + - sandbox-cors-proxy on :2468 (Node.js) + - No cloudflared - nginx handles SSL termination + +Garbage collection: 3-day retention (vs 14-day on darwin). +Disk guards: min-free 100MB, max-free 1GB. +Journald: 1-week retention. + + +8. DEPLOY COMMANDS +------------------- +Darwin (local): + just switch + +Netty (from mac): + just switch-netty + +First-time netty install: + nix run github:nix-community/nixos-anywhere -- \ + --flake .#netty --target-host netty --build-on-remote + + +9. ROLLBACK +------------- +Each phase is a separate git commit. + +NixOS rollback: + ssh netty "nixos-rebuild switch --rollback" + +Or boot previous generation from GRUB (3 kept). + +Darwin rollback: + git revert && just switch + +Home Manager rollback: + home-manager generations # list + home-manager switch --flake .# # after git revert + + +10. FEATURE FLAGS REFERENCE +----------------------------- +| Feature | darwin | netty | +|---------|--------|-------| +| rust | yes | yes | +| go | yes | yes | +| node | yes | yes | +| python | yes | yes | +| aws | yes | yes | +| claude | yes | yes | +| docker | yes | no | +| tex | yes | no | + +Set in lib/hosts.nix, consumed by home/xdg.nix and lib/package-sets.nix. From f59c9bb6d5d3af28e72fa0ea7019bd5a1c2309d8 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Mon, 30 Mar 2026 21:57:44 -0400 Subject: [PATCH 3/6] update --- nix-maxxing.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-maxxing.txt b/nix-maxxing.txt index d2683ce..4527b07 100644 --- a/nix-maxxing.txt +++ b/nix-maxxing.txt @@ -1,11 +1,11 @@ Nix Config - Architecture and Operations Guide ================================================ -1. WHY STATIC IP (NOT DHCP) +1. STATIC IP ---------------------------- DHCP on a VPS is dangerous. If the DHCP lease expires or the server reboots while the DHCP server is unreachable, the machine loses its IP -and becomes inaccessible via SSH. This happened on netty (2026-03-30). +and becomes inaccessible via SSH. Static config in hosts/netty/configuration.nix: - IP: 152.53.195.59/22 From b224a23656227341de83eed763e5dea619c13d20 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Mon, 30 Mar 2026 22:04:15 -0400 Subject: [PATCH 4/6] update terminal prompter --- config/agnoster.zsh-theme | 183 -------------------------------------- home/zsh.nix | 59 ++++++++---- lib/theme.nix | 44 +++++++++ nix-maxxing.txt | 4 +- 4 files changed, 88 insertions(+), 202 deletions(-) delete mode 100644 config/agnoster.zsh-theme diff --git a/config/agnoster.zsh-theme b/config/agnoster.zsh-theme deleted file mode 100644 index 7bbcebf..0000000 --- a/config/agnoster.zsh-theme +++ /dev/null @@ -1,183 +0,0 @@ -# vim:ft=zsh ts=2 sw=2 sts=2 -# -# agnoster's Theme - https://gist.github.com/3712874 -# A Powerline-inspired theme for ZSH - -### Segment drawing -CURRENT_BG='NONE' - -case ${SOLARIZED_THEME:-dark} in - light) - CURRENT_FG=${CURRENT_FG:-'white'} - CURRENT_DEFAULT_FG=${CURRENT_DEFAULT_FG:-'white'} - ;; - *) - CURRENT_FG=${CURRENT_FG:-'black'} - CURRENT_DEFAULT_FG=${CURRENT_DEFAULT_FG:-'default'} - ;; -esac - -### Theme Configuration Initialization -: ${AGNOSTER_DIR_FG:=${CURRENT_FG}} -: ${AGNOSTER_DIR_BG:=blue} - -: ${AGNOSTER_CONTEXT_FG:=${CURRENT_DEFAULT_FG}} -: ${AGNOSTER_CONTEXT_BG:=black} - -: ${AGNOSTER_GIT_CLEAN_FG:=${CURRENT_FG}} -: ${AGNOSTER_GIT_CLEAN_BG:=green} -: ${AGNOSTER_GIT_DIRTY_FG:=black} -: ${AGNOSTER_GIT_DIRTY_BG:=yellow} - -: ${AGNOSTER_BZR_CLEAN_FG:=${CURRENT_FG}} -: ${AGNOSTER_BZR_CLEAN_BG:=green} -: ${AGNOSTER_BZR_DIRTY_FG:=black} -: ${AGNOSTER_BZR_DIRTY_BG:=yellow} - -: ${AGNOSTER_HG_NEWFILE_FG:=white} -: ${AGNOSTER_HG_NEWFILE_BG:=red} -: ${AGNOSTER_HG_CHANGED_FG:=black} -: ${AGNOSTER_HG_CHANGED_BG:=yellow} -: ${AGNOSTER_HG_CLEAN_FG:=${CURRENT_FG}} -: ${AGNOSTER_HG_CLEAN_BG:=green} - -: ${AGNOSTER_VENV_FG:=black} -: ${AGNOSTER_VENV_BG:=blue} - -: ${AGNOSTER_AWS_PROD_FG:=yellow} -: ${AGNOSTER_AWS_PROD_BG:=red} -: ${AGNOSTER_AWS_FG:=black} -: ${AGNOSTER_AWS_BG:=green} - -: ${AGNOSTER_STATUS_RETVAL_FG:=red} -: ${AGNOSTER_STATUS_ROOT_FG:=yellow} -: ${AGNOSTER_STATUS_JOB_FG:=cyan} -: ${AGNOSTER_STATUS_FG:=${CURRENT_DEFAULT_FG}} -: ${AGNOSTER_STATUS_BG:=black} - -: ${AGNOSTER_STATUS_RETVAL_NUMERIC:=false} -: ${AGNOSTER_GIT_INLINE:=false} -: ${AGNOSTER_GIT_BRANCH_STATUS:=true} - -() { - local LC_ALL="" LC_CTYPE="en_US.UTF-8" - SEGMENT_SEPARATOR=$'\ue0b0' -} - -prompt_segment() { - local bg fg - [[ -n $1 ]] && bg="%K{$1}" || bg="%k" - [[ -n $2 ]] && fg="%F{$2}" || fg="%f" - if [[ $CURRENT_BG != 'NONE' && $1 != $CURRENT_BG ]]; then - echo -n " %{$bg%F{$CURRENT_BG}%}$SEGMENT_SEPARATOR%{$fg%} " - else - echo -n "%{$bg%}%{$fg%} " - fi - CURRENT_BG=$1 - [[ -n $3 ]] && echo -n $3 -} - -prompt_end() { - if [[ -n $CURRENT_BG ]]; then - echo -n " %{%k%F{$CURRENT_BG}%}$SEGMENT_SEPARATOR" - else - echo -n "%{%k%}" - fi - echo -n "%{%f%}" - CURRENT_BG='' -} - -git_toplevel() { - local repo_root=$(git rev-parse --show-toplevel) - if [[ $repo_root = '' ]]; then - repo_root=$(git rev-parse --git-dir) - [[ $repo_root = '.' ]] && repo_root=$PWD - fi - echo -n $repo_root -} - -### Prompt components - -prompt_context() { - if [[ -n "$SSH_CLIENT" ]]; then - prompt_segment "$AGNOSTER_CONTEXT_BG" "$AGNOSTER_CONTEXT_FG" "%(!.%{%F{$AGNOSTER_STATUS_ROOT_FG}%}.)%n@%m" - fi -} - -prompt_git_relative() { - local repo_root=$(git_toplevel) - local path_in_repo=$(pwd | sed "s/^$(echo "$repo_root" | sed 's:/:\\/:g;s/\$/\\$/g')//;s:^/::;s:/$::;") - [[ $path_in_repo != '' ]] && prompt_segment "$AGNOSTER_DIR_BG" "$AGNOSTER_DIR_FG" "$path_in_repo" -} - -prompt_git() { - (( $+commands[git] )) || return - [[ "$(command git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return - - local PL_BRANCH_CHAR - () { local LC_ALL="" LC_CTYPE="en_US.UTF-8"; PL_BRANCH_CHAR=$'\ue0a0' } - - if [[ "$(command git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]]; then - local dirty ref - dirty=$(parse_git_dirty) - ref=$(command git symbolic-ref HEAD 2>/dev/null) || \ - ref="➦ $(command git rev-parse --short HEAD 2>/dev/null)" - - if [[ -n $dirty ]]; then - prompt_segment "$AGNOSTER_GIT_DIRTY_BG" "$AGNOSTER_GIT_DIRTY_FG" - else - prompt_segment "$AGNOSTER_GIT_CLEAN_BG" "$AGNOSTER_GIT_CLEAN_FG" - fi - - echo -n "${${ref:gs/%/%%}/refs\/heads\//$PL_BRANCH_CHAR }" - fi -} - -prompt_dir() { - if [[ $AGNOSTER_GIT_INLINE == 'true' ]] && $(git rev-parse --is-inside-work-tree >/dev/null 2>&1); then - prompt_segment "$AGNOSTER_DIR_BG" "$AGNOSTER_DIR_FG" "$(git_toplevel | sed "s:^$HOME:~:")" - else - prompt_segment "$AGNOSTER_DIR_BG" "$AGNOSTER_DIR_FG" '%~' - fi -} - -prompt_virtualenv() { - return -} - -prompt_status() { - local -a symbols - [[ $AGNOSTER_STATUS_RETVAL_NUMERIC == 'true' && $RETVAL -ne 0 ]] && symbols+="%{%F{$AGNOSTER_STATUS_RETVAL_FG}%}$RETVAL" - [[ $AGNOSTER_STATUS_RETVAL_NUMERIC != 'true' && $RETVAL -ne 0 ]] && symbols+="%{%F{$AGNOSTER_STATUS_RETVAL_FG}%}✘" - [[ $UID -eq 0 ]] && symbols+="%{%F{$AGNOSTER_STATUS_ROOT_FG}%}⚡" - [[ $(jobs -l | wc -l) -gt 0 ]] && symbols+="%{%F{$AGNOSTER_STATUS_JOB_FG}%}⚙" - [[ -n "$symbols" ]] && prompt_segment "$AGNOSTER_STATUS_BG" "$AGNOSTER_STATUS_FG" "$symbols" -} - -prompt_aws() { - [[ -z "$AWS_PROFILE" || "$SHOW_AWS_PROMPT" = false ]] && return - case "$AWS_PROFILE" in - *-prod|*production*) prompt_segment "$AGNOSTER_AWS_PROD_BG" "$AGNOSTER_AWS_PROD_FG" "AWS: ${AWS_PROFILE:gs/%/%%}" ;; - *) prompt_segment "$AGNOSTER_AWS_BG" "$AGNOSTER_AWS_FG" "AWS: ${AWS_PROFILE:gs/%/%%}" ;; - esac -} - -prompt_terraform() { - local terraform_info=$(tf_prompt_info) - [[ -z "$terraform_info" ]] && return - prompt_segment magenta yellow "TF: $terraform_info" -} - -build_prompt() { - RETVAL=$? - prompt_status - prompt_virtualenv - prompt_aws - prompt_terraform - prompt_context - prompt_dir - prompt_git - prompt_end -} - -PROMPT='%{%f%b%k%}$(build_prompt) ' diff --git a/home/zsh.nix b/home/zsh.nix index dbc99c4..a7e7b39 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -9,13 +9,7 @@ let theme = import ../lib/theme.nix { inherit config; }; in { - home.file.".oh-my-zsh/custom/themes/agnoster.zsh-theme".source = ../config/agnoster.zsh-theme; - - home.activation.ensureOhMyZshCache = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - mkdir -p "${config.xdg.cacheHome}/oh-my-zsh" - ''; - - home.packages = [ pkgs.oh-my-zsh ]; + home.packages = [ pkgs.pure-prompt ]; programs.zsh = { enable = true; @@ -74,18 +68,30 @@ in initContent = lib.mkMerge [ (lib.mkOrder 550 '' - # OpenSpec shell completions configuration - fpath=("$HOME/.oh-my-zsh/custom/completions" $fpath) + # Completions + autoload -U compinit && compinit -d "${config.xdg.stateHome}/zcompdump" -u + zmodload zsh/complist + zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-za-z}' '') (lib.mkOrder 800 '' - export ZSH="${pkgs.oh-my-zsh}/share/oh-my-zsh" - export ZSH_CUSTOM="$HOME/.oh-my-zsh/custom" - export ZSH_CACHE_DIR="${config.xdg.cacheHome}/oh-my-zsh" - ZSH_THEME="agnoster" - plugins=(git) - ZSH_DISABLE_COMPFIX=true - source "$ZSH/oh-my-zsh.sh" + # Pure prompt + fpath+=("${pkgs.pure-prompt}/share/zsh/site-functions") + autoload -Uz promptinit && promptinit + + export PURE_PROMPT_SYMBOL=">" + export PURE_PROMPT_VICMD_SYMBOL="<" + export PURE_GIT_UP_ARROW="^" + export PURE_GIT_DOWN_ARROW="v" + export PURE_GIT_STASH_SYMBOL="=" + export PURE_CMD_MAX_EXEC_TIME=5 + export PURE_GIT_PULL=0 + export PURE_GIT_UNTRACKED_DIRTY=1 + zstyle ':prompt:pure:git:stash' show yes + + ${theme.renderPurePrompt "dark"} + + prompt pure '') (lib.mkOrder 1000 '' @@ -130,6 +136,21 @@ in printf 'dark' } + _codex_apply_prompt_theme() { + local mode="$(_codex_read_theme_mode)" + if [[ "$mode" == "''${_CODEX_LAST_PROMPT_THEME:-}" ]]; then + return + fi + + if [[ "$mode" == light ]]; then + ${theme.renderPurePrompt "light"} + else + ${theme.renderPurePrompt "dark"} + fi + + typeset -g _CODEX_LAST_PROMPT_THEME="$mode" + } + _codex_apply_highlight_styles() { local mode="$(_codex_read_theme_mode)" if [[ "$mode" == "''${_CODEX_LAST_HIGHLIGHT_THEME:-}" ]]; then @@ -192,6 +213,7 @@ in zle -N zle-line-finish precmd() { + _codex_apply_prompt_theme _codex_apply_highlight_styles _codex_set_cursor beam } @@ -200,6 +222,7 @@ in _codex_set_cursor beam } + _codex_apply_prompt_theme _codex_apply_highlight_styles ${lib.optionalString hostConfig.isDarwin '' @@ -216,8 +239,8 @@ in '') (lib.mkAfter '' - bindkey '^k' forward-car - bindkey '^j' backward-car + bindkey '^k' forward-char + bindkey '^j' backward-char '') ]; }; diff --git a/lib/theme.nix b/lib/theme.nix index f118017..37eba75 100644 --- a/lib/theme.nix +++ b/lib/theme.nix @@ -140,6 +140,49 @@ let --color=fg+:${theme.text},bg+:${theme.surface},hl+:${theme.blue} --color=info:${theme.green},prompt:${theme.blue},pointer:${theme.text},marker:${theme.green},spinner:${theme.text} ''; + renderPurePrompt = + mode: + let + theme = themes.${mode}; + c = if mode == "light" then { + path = "#4261a5"; + branch = "#427b58"; + dirty = sharedPalette.yellow; + arrow = sharedPalette.purpleNeutral; + stash = sharedPalette.aquaNeutral; + success = "#427b58"; + error = "#c5524a"; + execTime = sharedPalette.gray; + host = sharedPalette.gray; + user = sharedPalette.gray; + } else { + path = sharedPalette.blue; + branch = sharedPalette.green; + dirty = sharedPalette.yellowBright; + arrow = sharedPalette.purple; + stash = sharedPalette.aqua; + success = sharedPalette.green; + error = sharedPalette.red; + execTime = sharedPalette.gray; + host = sharedPalette.gray; + user = sharedPalette.gray; + }; + in + '' + zstyle ':prompt:pure:path' color '${c.path}' + zstyle ':prompt:pure:git:branch' color '${c.branch}' + zstyle ':prompt:pure:git:dirty' color '${c.dirty}' + zstyle ':prompt:pure:git:arrow' color '${c.arrow}' + zstyle ':prompt:pure:git:stash' color '${c.stash}' + zstyle ':prompt:pure:git:action' color '${c.dirty}' + zstyle ':prompt:pure:prompt:success' color '${c.success}' + zstyle ':prompt:pure:prompt:error' color '${c.error}' + zstyle ':prompt:pure:execution_time' color '${c.execTime}' + zstyle ':prompt:pure:host' color '${c.host}' + zstyle ':prompt:pure:user' color '${c.user}' + zstyle ':prompt:pure:user:root' color '${c.error}' + ''; + batTheme = mode: if mode == "light" then "gruvbox-light" else "gruvbox-dark"; deltaTheme = mode: if mode == "light" then "gruvbox-light" else "gruvbox-dark"; @@ -210,6 +253,7 @@ in paths renderFzf renderGhostty + renderPurePrompt renderTmux renderZshHighlights themes diff --git a/nix-maxxing.txt b/nix-maxxing.txt index 4527b07..10f4d47 100644 --- a/nix-maxxing.txt +++ b/nix-maxxing.txt @@ -86,7 +86,9 @@ and Neovim (via RPC) live. Bat and delta are static at build time. 6. SHELL SETUP --------------- -oh-my-zsh with agnoster theme (powerline arrows + git branch coloring). +Pure prompt with gruvbox-colored git integration. Async git status +(no blocking on large repos). Colors defined in lib/theme.nix via +renderPurePrompt - adapts to light/dark mode at runtime. Vim mode via defaultKeymap = "viins" with cursor shape switching (beam for insert, block for normal). From 4b436bdbfa92e207ceaa44f1ef258f4228a32a05 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Mon, 30 Mar 2026 22:39:20 -0400 Subject: [PATCH 5/6] prompter coloring and theme --- home/common.nix | 1 + home/default.nix | 23 ++++----- home/prompt.nix | 85 +++++++++++++++++++++++++++++++ home/zsh.nix | 96 ++++------------------------------- hosts/netty/configuration.nix | 6 ++- lib/package-sets.nix | 2 +- lib/theme.nix | 54 +++++++++++--------- modules/base.nix | 2 + 8 files changed, 146 insertions(+), 123 deletions(-) create mode 100644 home/prompt.nix diff --git a/home/common.nix b/home/common.nix index 9008cb4..cd53bdc 100644 --- a/home/common.nix +++ b/home/common.nix @@ -17,6 +17,7 @@ ./mise.nix ./migration.nix ./nvim.nix + ./prompt.nix ./skills.nix ./scripts.nix ./ssh.nix diff --git a/home/default.nix b/home/default.nix index ccd1fd7..e3fc1f0 100644 --- a/home/default.nix +++ b/home/default.nix @@ -4,16 +4,15 @@ ... }: { - imports = - [ - ./common.nix - ] - ++ lib.optionals hostConfig.isDarwin [ - ./colima.nix - ./rectangle.nix - ./karabiner.nix - ] - ++ lib.optionals hostConfig.isLinux [ - ./netty-worktree.nix - ]; + imports = [ + ./common.nix + ] + ++ lib.optionals hostConfig.isDarwin [ + ./colima.nix + ./rectangle.nix + ./karabiner.nix + ] + ++ lib.optionals hostConfig.isLinux [ + ./netty-worktree.nix + ]; } diff --git a/home/prompt.nix b/home/prompt.nix new file mode 100644 index 0000000..97ee72b --- /dev/null +++ b/home/prompt.nix @@ -0,0 +1,85 @@ +{ + config, + lib, + pkgs, + ... +}: +let + theme = import ../lib/theme.nix { inherit config; }; +in +{ + home.packages = [ pkgs.pure-prompt ]; + + programs.zsh.initContent = lib.mkMerge [ + (lib.mkOrder 800 '' + fpath+=("${pkgs.pure-prompt}/share/zsh/site-functions") + autoload -Uz promptinit && promptinit + + export PURE_PROMPT_SYMBOL=$'\xe2\x9d\xaf' + export PURE_PROMPT_VICMD_SYMBOL=$'\xe2\x9d\xae' + export PURE_GIT_DIRTY="" + export PURE_GIT_UP_ARROW="^" + export PURE_GIT_DOWN_ARROW="v" + export PURE_GIT_STASH_SYMBOL="=" + export PURE_CMD_MAX_EXEC_TIME=5 + export PURE_GIT_PULL=0 + export PURE_GIT_UNTRACKED_DIRTY=1 + zstyle ':prompt:pure:git:stash' show yes + + ${theme.renderPurePrompt "dark"} + + typeset -g prompt_newline=' ' + prompt pure + + prompt_pure_preprompt_render() { + setopt localoptions noshwordsplit + unset prompt_pure_async_render_requested + + typeset -g prompt_pure_git_branch_color=$prompt_pure_colors[git:branch] + [[ -n ''${prompt_pure_git_last_dirty_check_timestamp+x} ]] && prompt_pure_git_branch_color=$prompt_pure_colors[git:branch:cached] + + # Branch + arrows turn yellow when dirty + if [[ -n $prompt_pure_git_dirty ]]; then + prompt_pure_git_branch_color=$prompt_pure_colors[git:dirty] + prompt_pure_colors[git:arrow]=$prompt_pure_colors[git:dirty] + else + prompt_pure_colors[git:arrow]=$_codex_pure_default_arrow + fi + + psvar[12]=; ((''${(M)#jobstates:#suspended:*} != 0)) && psvar[12]=''${PURE_SUSPENDED_JOBS_SYMBOL:-✦} + psvar[13]=; [[ -n $prompt_pure_state[username] ]] && psvar[13]=1 + psvar[14]=''${prompt_pure_vcs_info[branch]} + psvar[15]= + psvar[16]=''${prompt_pure_vcs_info[action]} + psvar[17]=''${prompt_pure_git_arrows} + psvar[18]=; [[ -n $prompt_pure_git_stash ]] && psvar[18]=1 + psvar[19]=''${prompt_pure_cmd_exec_time} + + local expanded_prompt + expanded_prompt="''${(S%%)PROMPT}" + + if [[ $1 != precmd && $prompt_pure_last_prompt != $expanded_prompt ]]; then + prompt_pure_reset_prompt + fi + + typeset -g prompt_pure_last_prompt=$expanded_prompt + } + + typeset -g _codex_pure_default_arrow=$prompt_pure_colors[git:arrow] + + _codex_apply_prompt_theme() { + local mode="$(_codex_read_theme_mode)" + [[ "$mode" == "''${_CODEX_LAST_PROMPT_THEME:-}" ]] && return + + if [[ "$mode" == light ]]; then + ${theme.renderPurePrompt "light"} + else + ${theme.renderPurePrompt "dark"} + fi + + typeset -g _codex_pure_default_arrow=$prompt_pure_colors[git:arrow] + typeset -g _CODEX_LAST_PROMPT_THEME="$mode" + } + '') + ]; +} diff --git a/home/zsh.nix b/home/zsh.nix index a7e7b39..ce65475 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -9,8 +9,6 @@ let theme = import ../lib/theme.nix { inherit config; }; in { - home.packages = [ pkgs.pure-prompt ]; - programs.zsh = { enable = true; dotDir = config.home.homeDirectory; @@ -58,8 +56,6 @@ in export NODE_NO_WARNINGS=1 '' + lib.optionalString hostConfig.isDarwin '' - # Ghostty shell integration expects a resource directory; the Nix app - # bundle lives in the store instead of /Applications. export GHOSTTY_RESOURCES_DIR="${pkgs.ghostty-bin}/Applications/Ghostty.app/Contents/Resources/ghostty" '' + '' @@ -68,32 +64,11 @@ in initContent = lib.mkMerge [ (lib.mkOrder 550 '' - # Completions autoload -U compinit && compinit -d "${config.xdg.stateHome}/zcompdump" -u zmodload zsh/complist zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-za-z}' '') - (lib.mkOrder 800 '' - # Pure prompt - fpath+=("${pkgs.pure-prompt}/share/zsh/site-functions") - autoload -Uz promptinit && promptinit - - export PURE_PROMPT_SYMBOL=">" - export PURE_PROMPT_VICMD_SYMBOL="<" - export PURE_GIT_UP_ARROW="^" - export PURE_GIT_DOWN_ARROW="v" - export PURE_GIT_STASH_SYMBOL="=" - export PURE_CMD_MAX_EXEC_TIME=5 - export PURE_GIT_PULL=0 - export PURE_GIT_UNTRACKED_DIRTY=1 - zstyle ':prompt:pure:git:stash' show yes - - ${theme.renderPurePrompt "dark"} - - prompt pure - '') - (lib.mkOrder 1000 '' if [[ -f ~/.config/secrets/shell.zsh ]]; then source ~/.config/secrets/shell.zsh @@ -132,39 +107,19 @@ in return fi fi - printf 'dark' } - _codex_apply_prompt_theme() { - local mode="$(_codex_read_theme_mode)" - if [[ "$mode" == "''${_CODEX_LAST_PROMPT_THEME:-}" ]]; then - return - fi - - if [[ "$mode" == light ]]; then - ${theme.renderPurePrompt "light"} - else - ${theme.renderPurePrompt "dark"} - fi - - typeset -g _CODEX_LAST_PROMPT_THEME="$mode" - } - _codex_apply_highlight_styles() { local mode="$(_codex_read_theme_mode)" - if [[ "$mode" == "''${_CODEX_LAST_HIGHLIGHT_THEME:-}" ]]; then - return - fi + [[ "$mode" == "''${_CODEX_LAST_HIGHLIGHT_THEME:-}" ]] && return typeset -gA ZSH_HIGHLIGHT_STYLES - if [[ "$mode" == light ]]; then ${theme.renderZshHighlights "light"} else ${theme.renderZshHighlights "dark"} fi - typeset -g _CODEX_LAST_HIGHLIGHT_THEME="$mode" } @@ -173,7 +128,6 @@ in git() { command git "$@" local exit_code=$? - case "$1" in add|stage|reset|checkout) if command -v critic >/dev/null 2>&1; then @@ -181,46 +135,23 @@ in fi ;; esac - return $exit_code } - function _codex_set_cursor { - if [[ "$1" == block ]]; then - printf '\e[2 q' - else - printf '\e[6 q' - fi - } - - function zle-keymap-select { - if [[ "$KEYMAP" == vicmd ]]; then - _codex_set_cursor block - else - _codex_set_cursor beam - fi - } - zle -N zle-keymap-select - - function zle-line-init { - _codex_set_cursor beam - } - zle -N zle-line-init - - function zle-line-finish { - _codex_set_cursor beam - } - zle -N zle-line-finish + autoload -Uz add-zle-hook-widget + _codex_cursor() { printf '\e[%s q' "''${1:-6}"; } + _codex_cursor_select() { [[ "$KEYMAP" == vicmd ]] && _codex_cursor 2 || _codex_cursor 6; } + _codex_cursor_beam() { _codex_cursor 6; } + add-zle-hook-widget zle-keymap-select _codex_cursor_select + add-zle-hook-widget zle-line-init _codex_cursor_beam + add-zle-hook-widget zle-line-finish _codex_cursor_beam precmd() { _codex_apply_prompt_theme _codex_apply_highlight_styles - _codex_set_cursor beam - } - - preexec() { - _codex_set_cursor beam + _codex_cursor_beam } + preexec() { _codex_cursor_beam; } _codex_apply_prompt_theme _codex_apply_highlight_styles @@ -228,12 +159,7 @@ in ${lib.optionalString hostConfig.isDarwin '' if command -v wt >/dev/null 2>&1; then eval "$(command wt config shell init zsh)" - - # `wt` changes directories by sourcing directives into the current shell, - # so wrappers around it must stay shell functions instead of scripts. - wtc() { - wt switch --create --base @ "$@" - } + wtc() { wt switch --create --base @ "$@"; } fi ''} '') diff --git a/hosts/netty/configuration.nix b/hosts/netty/configuration.nix index ec08f18..fd7c410 100644 --- a/hosts/netty/configuration.nix +++ b/hosts/netty/configuration.nix @@ -173,7 +173,11 @@ in Type = "oneshot"; EnvironmentFile = "/etc/forgejo-mirror.env"; }; - path = [ pkgs.curl pkgs.jq pkgs.coreutils ]; + path = [ + pkgs.curl + pkgs.jq + pkgs.coreutils + ]; script = '' set -euo pipefail diff --git a/lib/package-sets.nix b/lib/package-sets.nix index 5228e15..ebd0033 100644 --- a/lib/package-sets.nix +++ b/lib/package-sets.nix @@ -108,7 +108,7 @@ in ]) ++ lib.optionals pkgs.stdenv.isDarwin [ agentcomputerPackage - texliveFull + pkgs.texliveFull ] ++ [ openspecPackage diff --git a/lib/theme.nix b/lib/theme.nix index 37eba75..37eb113 100644 --- a/lib/theme.nix +++ b/lib/theme.nix @@ -144,29 +144,33 @@ let mode: let theme = themes.${mode}; - c = if mode == "light" then { - path = "#4261a5"; - branch = "#427b58"; - dirty = sharedPalette.yellow; - arrow = sharedPalette.purpleNeutral; - stash = sharedPalette.aquaNeutral; - success = "#427b58"; - error = "#c5524a"; - execTime = sharedPalette.gray; - host = sharedPalette.gray; - user = sharedPalette.gray; - } else { - path = sharedPalette.blue; - branch = sharedPalette.green; - dirty = sharedPalette.yellowBright; - arrow = sharedPalette.purple; - stash = sharedPalette.aqua; - success = sharedPalette.green; - error = sharedPalette.red; - execTime = sharedPalette.gray; - host = sharedPalette.gray; - user = sharedPalette.gray; - }; + c = + if mode == "light" then + { + path = "#4261a5"; + branch = "#427b58"; + dirty = sharedPalette.yellow; + arrow = sharedPalette.purpleNeutral; + stash = sharedPalette.aquaNeutral; + success = "#427b58"; + error = "#c5524a"; + execTime = sharedPalette.gray; + host = sharedPalette.gray; + user = sharedPalette.gray; + } + else + { + path = sharedPalette.blue; + branch = sharedPalette.green; + dirty = sharedPalette.yellowBright; + arrow = sharedPalette.purple; + stash = sharedPalette.aqua; + success = sharedPalette.green; + error = sharedPalette.red; + execTime = sharedPalette.gray; + host = sharedPalette.gray; + user = sharedPalette.gray; + }; in '' zstyle ':prompt:pure:path' color '${c.path}' @@ -228,7 +232,9 @@ let ZSH_HIGHLIGHT_STYLES[bracket-level-5]='fg=${if mode == "light" then c.aqua else c.aqua},bold' ZSH_HIGHLIGHT_STYLES[comment]='fg=${c.comment}' ZSH_HIGHLIGHT_STYLES[command-substitution-delimiter]='fg=${c.purple}' - ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=${if mode == "light" then c.aqua else c.aqua}' + ZSH_HIGHLIGHT_STYLES[dollar-double-quoted-argument]='fg=${ + if mode == "light" then c.aqua else c.aqua + }' ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=${c.yellow}' ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=${c.yellow}' ZSH_HIGHLIGHT_STYLES[global-alias]='fg=${if mode == "light" then c.aqua else c.aqua}' diff --git a/modules/base.nix b/modules/base.nix index 6e22765..56fc61d 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -22,6 +22,8 @@ in username ]; use-xdg-base-directories = true; + max-jobs = "auto"; + cores = 0; }; nix.gc = { From 23f876dc7ca981438a86f751a32f6bf39cbed2a9 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Mon, 30 Mar 2026 22:59:49 -0400 Subject: [PATCH 6/6] clean wt rm etc --- ci/agentcomputer-cli-stub/flake.nix | 30 ----------- docs/secrets.md | 80 ----------------------------- flake.nix | 7 +-- home/bat.nix | 5 +- home/common.nix | 4 +- home/fzf.nix | 5 +- home/ghostty.nix | 3 +- home/git.nix | 5 +- home/prompt.nix | 11 ++-- home/tmux.nix | 5 +- home/zsh.nix | 10 +--- lib/package-sets.nix | 53 ------------------- 12 files changed, 16 insertions(+), 202 deletions(-) delete mode 100644 ci/agentcomputer-cli-stub/flake.nix delete mode 100644 docs/secrets.md diff --git a/ci/agentcomputer-cli-stub/flake.nix b/ci/agentcomputer-cli-stub/flake.nix deleted file mode 100644 index aafbc22..0000000 --- a/ci/agentcomputer-cli-stub/flake.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - description = "CI stub for the local agentcomputer-cli flake input"; - - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - - outputs = - { nixpkgs, ... }: - let - systems = [ - "aarch64-darwin" - "x86_64-darwin" - "aarch64-linux" - "x86_64-linux" - ]; - forAllSystems = nixpkgs.lib.genAttrs systems; - in - { - packages = forAllSystems ( - system: - let - pkgs = import nixpkgs { inherit system; }; - in - { - default = pkgs.writeShellScriptBin "aicomputer" '' - echo "agentcomputer-cli CI stub" - ''; - } - ); - }; -} diff --git a/docs/secrets.md b/docs/secrets.md deleted file mode 100644 index 0b0af72..0000000 --- a/docs/secrets.md +++ /dev/null @@ -1,80 +0,0 @@ -# Secrets - -## Current Model - -This repo does not store secret values in Nix. - -Instead: - -- Bitwarden vault items are the current source of truth for imported machine - secrets -- Nix/Home Manager owns the integration points -- generated runtime files live outside the repo under `~/.config/secrets` - -That boundary matters because the Nix store is not the right place for real -secret values. - -## What Is Already Wired - -- [home/zsh.nix](/Users/rathi/Documents/GitHub/nix/home/zsh.nix) sources - `~/.config/secrets/shell.zsh` when present -- [scripts/render-bw-shell-secrets.sh](/Users/rathi/Documents/GitHub/nix/scripts/render-bw-shell-secrets.sh) - renders that file from Bitwarden vault items -- [scripts/restore-bw-files.sh](/Users/rathi/Documents/GitHub/nix/scripts/restore-bw-files.sh) - restores file-based credentials and SSH material from Bitwarden vault items -- [justfile](/Users/rathi/Documents/GitHub/nix/justfile) exposes this as - `just secrets-sync` and `just secrets-restore-files` - -## Daily Shell Flow - -```bash -export BW_SESSION="$(bw unlock --raw)" -just secrets-sync -exec zsh -l -``` - -That flow currently materializes: - -- `OPENAI_API_KEY` -- `GREPTILE_API_KEY` -- `CONTEXT7_API_KEY` -- `MISTRAL_API_KEY` - -## Machine Secret Coverage - -The Bitwarden vault now holds: - -- API keys and CLI tokens -- AWS default credentials -- GCloud ADC -- Stripe CLI config -- Codex auth -- Vercel auth -- SSH configs -- SSH private keys - -The vault is currently the backup/recovery source of truth for those values. - -## Sandbox Strategy - -For a fresh sandbox or new machine, the clean bootstrap is: - -1. `darwin-rebuild switch` or Home Manager activation -2. authenticate `bw` -3. `just secrets-sync` -4. `just secrets-restore-files` - -That gives you a usable dev shell quickly without committing any secret values -into the repo. - -## Future Upgrade - -If you want fully non-interactive sandbox secret injection, the next step is to -move the env-style secrets from normal Bitwarden vault items into Bitwarden -Secrets Manager (`bws`) and keep file-based credentials and SSH material in the -normal vault. - -That would give you: - -- `bws` for machine/app secrets -- `bw` for human-managed vault items, SSH material, and recovery data diff --git a/flake.nix b/flake.nix index 5b340ef..d38b59b 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Rathi's macOS nix-darwin + NixOS + Home Manager config"; + description = "Hari's nix config"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; @@ -25,11 +25,6 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - agentcomputer-cli = { - url = "path:/Users/rathi/Documents/GitHub/companion/agentcomputer/apps/cli"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - openspec = { url = "github:Fission-AI/OpenSpec"; }; diff --git a/home/bat.nix b/home/bat.nix index 50f1b76..a7a1fc2 100644 --- a/home/bat.nix +++ b/home/bat.nix @@ -1,7 +1,4 @@ -{ config, ... }: -let - theme = import ../lib/theme.nix { inherit config; }; -in +{ theme, ... }: { programs.bat = { enable = true; diff --git a/home/common.nix b/home/common.nix index cd53bdc..eba4f83 100644 --- a/home/common.nix +++ b/home/common.nix @@ -1,5 +1,7 @@ -{ ... }: +{ config, ... }: { + _module.args.theme = import ../lib/theme.nix { inherit config; }; + imports = [ ./bat.nix ./eza.nix diff --git a/home/fzf.nix b/home/fzf.nix index be0c859..08d5d74 100644 --- a/home/fzf.nix +++ b/home/fzf.nix @@ -1,7 +1,4 @@ -{ config, ... }: -let - theme = import ../lib/theme.nix { inherit config; }; -in +{ theme, ... }: { home.sessionVariables = { FZF_DEFAULT_OPTS_FILE = theme.paths.fzfCurrentFile; diff --git a/home/ghostty.nix b/home/ghostty.nix index dd768df..5e611e6 100644 --- a/home/ghostty.nix +++ b/home/ghostty.nix @@ -1,12 +1,11 @@ { - config, lib, pkgs, hostConfig, + theme, ... }: let - theme = import ../lib/theme.nix { inherit config; }; ghosttyConfig = '' theme = "cozybox-current" font-family = Berkeley Mono diff --git a/home/git.nix b/home/git.nix index 8ef05d2..dc1bfcc 100644 --- a/home/git.nix +++ b/home/git.nix @@ -1,7 +1,4 @@ -{ config, ... }: -let - theme = import ../lib/theme.nix { inherit config; }; -in +{ theme, ... }: { programs.git = { enable = true; diff --git a/home/prompt.nix b/home/prompt.nix index 97ee72b..5dafdc9 100644 --- a/home/prompt.nix +++ b/home/prompt.nix @@ -1,12 +1,9 @@ { - config, lib, pkgs, + theme, ... }: -let - theme = import ../lib/theme.nix { inherit config; }; -in { home.packages = [ pkgs.pure-prompt ]; @@ -38,12 +35,14 @@ in typeset -g prompt_pure_git_branch_color=$prompt_pure_colors[git:branch] [[ -n ''${prompt_pure_git_last_dirty_check_timestamp+x} ]] && prompt_pure_git_branch_color=$prompt_pure_colors[git:branch:cached] - # Branch + arrows turn yellow when dirty + # Branch, arrows, and prompt symbol turn yellow when dirty if [[ -n $prompt_pure_git_dirty ]]; then prompt_pure_git_branch_color=$prompt_pure_colors[git:dirty] prompt_pure_colors[git:arrow]=$prompt_pure_colors[git:dirty] + prompt_pure_colors[prompt:success]=$prompt_pure_colors[git:dirty] else prompt_pure_colors[git:arrow]=$_codex_pure_default_arrow + prompt_pure_colors[prompt:success]=$_codex_pure_default_success fi psvar[12]=; ((''${(M)#jobstates:#suspended:*} != 0)) && psvar[12]=''${PURE_SUSPENDED_JOBS_SYMBOL:-✦} @@ -66,6 +65,7 @@ in } typeset -g _codex_pure_default_arrow=$prompt_pure_colors[git:arrow] + typeset -g _codex_pure_default_success=$prompt_pure_colors[prompt:success] _codex_apply_prompt_theme() { local mode="$(_codex_read_theme_mode)" @@ -78,6 +78,7 @@ in fi typeset -g _codex_pure_default_arrow=$prompt_pure_colors[git:arrow] + typeset -g _codex_pure_default_success=$prompt_pure_colors[prompt:success] typeset -g _CODEX_LAST_PROMPT_THEME="$mode" } '') diff --git a/home/tmux.nix b/home/tmux.nix index c6662b9..d6bf988 100644 --- a/home/tmux.nix +++ b/home/tmux.nix @@ -1,12 +1,9 @@ { - config, lib, pkgs, + theme, ... }: -let - theme = import ../lib/theme.nix { inherit config; }; -in { programs.tmux = { enable = true; diff --git a/home/zsh.nix b/home/zsh.nix index ce65475..b2ae327 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -3,11 +3,9 @@ lib, pkgs, hostConfig, + theme, ... }: -let - theme = import ../lib/theme.nix { inherit config; }; -in { programs.zsh = { enable = true; @@ -156,12 +154,6 @@ in _codex_apply_prompt_theme _codex_apply_highlight_styles - ${lib.optionalString hostConfig.isDarwin '' - if command -v wt >/dev/null 2>&1; then - eval "$(command wt config shell init zsh)" - wtc() { wt switch --create --base @ "$@"; } - fi - ''} '') (lib.mkAfter '' diff --git a/lib/package-sets.nix b/lib/package-sets.nix index ebd0033..8e8aff1 100644 --- a/lib/package-sets.nix +++ b/lib/package-sets.nix @@ -6,56 +6,8 @@ let gwsPackage = inputs.googleworkspace-cli.packages.${pkgs.stdenv.hostPlatform.system}.default; claudePackage = inputs.claudeCode.packages.${pkgs.stdenv.hostPlatform.system}.default; - agentcomputerPackage = inputs.agentcomputer-cli.packages.${pkgs.stdenv.hostPlatform.system}.default; openspecPackage = inputs.openspec.packages.${pkgs.stdenv.hostPlatform.system}.default; - graphite = pkgs.stdenvNoCC.mkDerivation rec { - pname = "graphite"; - version = "1.7.20"; - - src = pkgs.fetchurl { - url = "https://github.com/withgraphite/homebrew-tap/releases/download/v${version}/gt-macos-arm64"; - hash = "sha256-ho9VQw1ic3jhG3yxNwUL0W1WvNFku9zw6DQnGehs7+8="; - }; - - dontUnpack = true; - - installPhase = '' - install -Dm755 "$src" "$out/bin/gt" - ''; - - meta = { - description = "Manage stacked Git changes and submit them for review"; - homepage = "https://graphite.dev/"; - license = lib.licenses.agpl3Only; - mainProgram = "gt"; - platforms = lib.platforms.darwin; - }; - }; - - worktrunk = pkgs.rustPlatform.buildRustPackage rec { - pname = "worktrunk"; - version = "0.23.1"; - - src = pkgs.fetchurl { - url = "https://github.com/max-sixty/worktrunk/archive/refs/tags/v${version}.tar.gz"; - hash = "sha256-cdQDUz7to3JkriWE9i5iJ2RftJFZivw7CTwGxDZPAqw="; - }; - - cargoHash = "sha256-DHjwNqMiVkWqL3CuOCITvyqkdKe+GOZ2nlMSstDIcTg="; - doCheck = false; - - meta = { - description = "CLI for Git worktree management"; - homepage = "https://worktrunk.dev"; - license = with lib.licenses; [ - asl20 - mit - ]; - mainProgram = "wt"; - platforms = lib.platforms.darwin; - }; - }; in { core = with pkgs; [ @@ -107,15 +59,10 @@ in yt-dlp ]) ++ lib.optionals pkgs.stdenv.isDarwin [ - agentcomputerPackage pkgs.texliveFull ] ++ [ openspecPackage - ] - ++ lib.optionals pkgs.stdenv.isDarwin [ - graphite - worktrunk ]; fonts = with pkgs; [