diff --git a/README.md b/README.md index 7700ec8..f1fde26 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Approach This repo is the source of truth for the machine's reproducible developer -environment: +environment across macOS and Linux: - `home/` contains the Home Manager modules for user-facing tools - `config/` contains the repo-owned config trees copied from your daily setup @@ -12,16 +12,21 @@ environment: that are still easier to keep in Brew on macOS - `home/migration.nix` contains one-time ownership handoff logic from `~/dots` into Home Manager so the steady-state modules can stay focused on real config +- `lib/package-sets.nix` defines the shared CLI package subsets used by both + macOS and Linux hosts ## Layout - `flake.nix`: top-level flake and host wiring - `hosts/hari-macbook-pro/default.nix`: this machine's host config +- `hosts/workstation/default.nix`: standalone Linux Home Manager host config - `modules/base.nix`: Nix settings and core packages - `modules/macos.nix`: macOS defaults and host-level settings - `modules/packages.nix`: system packages and fonts - `modules/homebrew.nix`: the remaining Homebrew-managed GUI apps - `home/`: Home Manager modules for shell, editor, CLI tools, and app config +- `home/common.nix`: shared Home Manager imports used by macOS and Linux +- `home/linux.nix`: Linux Home Manager entrypoint - `home/migration.nix`: transitional cleanup for old `~/dots` symlinks - `config/`: repo-owned config files consumed by Home Manager @@ -57,14 +62,22 @@ Bitwarden note: First switch: ```bash -nix run github:LnL7/nix-darwin/master#darwin-rebuild -- switch --flake .#hari-macbook-pro +nix run github:LnL7/nix-darwin/master#darwin-rebuild -- switch --flake path:.#hari-macbook-pro +``` + +First Linux switch: + +```bash +nix run github:nix-community/home-manager -- switch --flake path:.#workstation -b hm-bak ``` After the first successful switch: ```bash just switch +just switch workstation just build +just build workstation just check ``` diff --git a/flake.nix b/flake.nix index 36de3c9..724e241 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Rathi's macOS nix-darwin + Home Manager config"; + description = "Rathi's macOS nix-darwin + Linux Home Manager config"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; @@ -38,18 +38,28 @@ nix-homebrew, ... }: let - system = "aarch64-darwin"; + darwinSystem = "aarch64-darwin"; + linuxSystem = "x86_64-linux"; username = "rathi"; - hostname = "hari-macbook-pro"; - pkgs = import nixpkgs {inherit system;}; + darwinHostname = "hari-macbook-pro"; + linuxHostname = "workstation"; + darwinPkgs = import nixpkgs {system = darwinSystem;}; + linuxPkgs = import nixpkgs { + system = linuxSystem; + config.allowUnfree = true; + }; in { - formatter.${system} = pkgs.alejandra; + formatter.${darwinSystem} = darwinPkgs.alejandra; + formatter.${linuxSystem} = linuxPkgs.alejandra; - darwinConfigurations.${hostname} = nix-darwin.lib.darwinSystem { - inherit system; - specialArgs = {inherit inputs self username hostname;}; + darwinConfigurations.${darwinHostname} = nix-darwin.lib.darwinSystem { + system = darwinSystem; + specialArgs = { + inherit inputs self username; + hostname = darwinHostname; + }; modules = [ - ./hosts/${hostname} + ./hosts/${darwinHostname} home-manager.darwinModules.home-manager nix-homebrew.darwinModules.nix-homebrew { @@ -57,7 +67,10 @@ home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; - home-manager.extraSpecialArgs = {inherit inputs self username hostname;}; + home-manager.extraSpecialArgs = { + inherit inputs self username; + hostname = darwinHostname; + }; home-manager.backupFileExtension = "hm-bak"; home-manager.users.${username} = import ./home; @@ -70,5 +83,16 @@ } ]; }; + + homeConfigurations.${linuxHostname} = home-manager.lib.homeManagerConfiguration { + pkgs = linuxPkgs; + extraSpecialArgs = { + inherit inputs self username; + hostname = linuxHostname; + }; + modules = [ + ./hosts/${linuxHostname} + ]; + }; }; } diff --git a/home/common.nix b/home/common.nix new file mode 100644 index 0000000..2a05927 --- /dev/null +++ b/home/common.nix @@ -0,0 +1,24 @@ +{...}: { + imports = [ + ./bat.nix + ./eza.nix + ./claude.nix + ./codex.nix + ./fzf.nix + ./gcloud.nix + ./gh.nix + ./ghostty.nix + ./git.nix + ./k9s.nix + ./lazygit.nix + ./migration.nix + ./nvim.nix + ./scripts.nix + ./tmux.nix + ./zsh.nix + ]; + + home.stateVersion = "24.11"; + programs.home-manager.enable = true; + xdg.enable = true; +} diff --git a/home/default.nix b/home/default.nix index bf89cf6..630b162 100644 --- a/home/default.nix +++ b/home/default.nix @@ -1,26 +1,7 @@ {...}: { imports = [ - ./bat.nix - ./eza.nix - ./claude.nix - ./codex.nix - ./fzf.nix - ./gcloud.nix - ./gh.nix - ./ghostty.nix - ./git.nix + ./common.nix ./karabiner.nix - ./k9s.nix - ./lazygit.nix - ./migration.nix - ./nvim.nix ./rectangle.nix - ./scripts.nix - ./tmux.nix - ./zsh.nix ]; - - home.stateVersion = "24.11"; - programs.home-manager.enable = true; - xdg.enable = true; } diff --git a/home/ghostty.nix b/home/ghostty.nix index 13e359b..6616258 100644 --- a/home/ghostty.nix +++ b/home/ghostty.nix @@ -1,5 +1,6 @@ { config, + lib, pkgs, ... }: let @@ -38,8 +39,10 @@ keybind = vim/i=deactivate_key_table keybind = vim/catch_all=ignore mouse-hide-while-typing = true - macos-titlebar-style = hidden - macos-option-as-alt = true + ${lib.optionalString pkgs.stdenv.isDarwin '' + macos-titlebar-style = hidden + macos-option-as-alt = true + ''} confirm-close-surface = true window-title-font-family = VictorMono NFM Italic window-padding-balance = true @@ -52,7 +55,10 @@ in { programs.ghostty = { enable = true; - package = pkgs.ghostty-bin; + package = + if pkgs.stdenv.isDarwin + then pkgs.ghostty-bin + else pkgs.ghostty; installBatSyntax = true; }; @@ -64,8 +70,10 @@ in { xdg.configFile."ghostty/themes/cozybox-dark".text = theme.renderGhostty "dark"; xdg.configFile."ghostty/themes/cozybox-light".text = theme.renderGhostty "light"; - home.file."Library/Application Support/com.mitchellh.ghostty/config.ghostty" = { - text = ghosttyConfig; - force = true; + home.file = lib.mkIf pkgs.stdenv.isDarwin { + "Library/Application Support/com.mitchellh.ghostty/config.ghostty" = { + text = ghosttyConfig; + force = true; + }; }; } diff --git a/home/lazygit.nix b/home/lazygit.nix index b90420f..fa65e09 100644 --- a/home/lazygit.nix +++ b/home/lazygit.nix @@ -1,4 +1,12 @@ -{...}: { - home.file."Library/Application Support/lazygit/config.yml".source = - ../config/lazygit/config.yml; +{ + lib, + pkgs, + ... +}: { + xdg.configFile."lazygit/config.yml".source = ../config/lazygit/config.yml; + + home.file = lib.mkIf pkgs.stdenv.isDarwin { + "Library/Application Support/lazygit/config.yml".source = + ../config/lazygit/config.yml; + }; } diff --git a/home/linux.nix b/home/linux.nix new file mode 100644 index 0000000..af72e74 --- /dev/null +++ b/home/linux.nix @@ -0,0 +1,5 @@ +{...}: { + imports = [ + ./common.nix + ]; +} diff --git a/home/zsh.nix b/home/zsh.nix index 683e046..19e0e05 100644 --- a/home/zsh.nix +++ b/home/zsh.nix @@ -22,43 +22,53 @@ autosuggestion.enable = true; syntaxHighlighting.enable = true; - shellAliases = { - co = "codex --dangerously-bypass-approvals-and-sandbox"; - ca = "cursor-agent"; - cc = "claude"; - ch = "claude-handoff"; - cl = "clear"; - gc = "git commit"; - gd = "git diff"; - gk = "git checkout"; - gp = "git push"; - gpo = "git pull origin"; - gs = "git status"; - ld = "lumen diff"; - lg = "lazygit"; - nim = "nvim ."; - sshnet = "ssh -i ~/.ssh/atlas-ssh.txt rathiharivansh@152.53.195.59"; - tailscale = "/Applications/Tailscale.app/Contents/MacOS/Tailscale"; + shellAliases = + { + co = "codex --dangerously-bypass-approvals-and-sandbox"; + ca = "cursor-agent"; + cc = "claude"; + ch = "claude-handoff"; + cl = "clear"; + gc = "git commit"; + gd = "git diff"; + gk = "git checkout"; + gp = "git push"; + gpo = "git pull origin"; + gs = "git status"; + ld = "lumen diff"; + lg = "lazygit"; + nim = "nvim ."; + sshnet = "ssh -i ~/.ssh/atlas-ssh.txt rathiharivansh@152.53.195.59"; - # nix helpers - nr = "nix profile remove"; # nr - remove from profile - ns = "nix search nixpkgs"; # ns - search packages - nls = "nix profile list"; # nls - list installed profile packages - nrb = "sudo darwin-rebuild switch --flake ~/Documents/GitHub/nix"; # nrb - rebuild declarative config - nup = "nix flake update ~/Documents/GitHub/nix && sudo darwin-rebuild switch --flake ~/Documents/GitHub/nix"; # nup - update flake + rebuild + # nix helpers + nr = "nix profile remove"; # nr - remove from profile + ns = "nix search nixpkgs"; # ns - search packages + nls = "nix profile list"; # nls - list installed profile packages + } + // lib.optionalAttrs pkgs.stdenv.isDarwin { + tailscale = "/Applications/Tailscale.app/Contents/MacOS/Tailscale"; + nrb = "sudo darwin-rebuild switch --flake path:$HOME/Documents/GitHub/nix#hari-macbook-pro"; # nrb - rebuild declarative config + nup = "nix flake update $HOME/Documents/GitHub/nix && sudo darwin-rebuild switch --flake path:$HOME/Documents/GitHub/nix#hari-macbook-pro"; # nup - update flake + rebuild + } + // lib.optionalAttrs pkgs.stdenv.isLinux { + nrb = "nix run github:nix-community/home-manager -- switch --flake path:$HOME/Documents/GitHub/nix#workstation -b hm-bak"; # nrb - rebuild declarative config + nup = "nix flake update $HOME/Documents/GitHub/nix && nix run github:nix-community/home-manager -- switch --flake path:$HOME/Documents/GitHub/nix#workstation -b hm-bak"; # nup - update flake + rebuild }; - envExtra = '' - if [[ -f "$HOME/.cargo/env" ]]; then - . "$HOME/.cargo/env" - fi - - # 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" - - export MANPAGER="nvim +Man!" - ''; + envExtra = + '' + if [[ -f "$HOME/.cargo/env" ]]; then + . "$HOME/.cargo/env" + fi + '' + + lib.optionalString pkgs.stdenv.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" + '' + + '' + export MANPAGER="nvim +Man!" + ''; initContent = lib.mkMerge [ (lib.mkOrder 550 '' @@ -88,7 +98,11 @@ [ -s "$HOME/.bun/_bun" ] && source "$HOME/.bun/_bun" export BUN_INSTALL="$HOME/.bun" - export PNPM_HOME="$HOME/Library/pnpm" + export PNPM_HOME="${ + if pkgs.stdenv.isDarwin + then "$HOME/Library/pnpm" + else "${config.xdg.dataHome}/pnpm" + }" bindkey -v typeset -U path PATH path=( @@ -103,8 +117,10 @@ "/etc/profiles/per-user/${config.home.username}/bin" "/run/current-system/sw/bin" "/nix/var/nix/profiles/default/bin" + ${lib.optionalString pkgs.stdenv.isDarwin '' "/opt/homebrew/bin" "/opt/homebrew/sbin" + ''} $path ) diff --git a/hosts/workstation/default.nix b/hosts/workstation/default.nix new file mode 100644 index 0000000..642821a --- /dev/null +++ b/hosts/workstation/default.nix @@ -0,0 +1,21 @@ +{ + inputs, + lib, + pkgs, + username, + ... +}: let + packageSets = import ../../lib/package-sets.nix {inherit inputs lib pkgs;}; +in { + imports = [ + ../../home/linux.nix + ]; + + targets.genericLinux.enable = true; + + home = { + inherit username; + homeDirectory = "/home/${username}"; + packages = packageSets.core ++ packageSets.extras; + }; +} diff --git a/justfile b/justfile index 67d73d5..6002b1c 100644 --- a/justfile +++ b/justfile @@ -4,11 +4,21 @@ default: check: nix --extra-experimental-features 'nix-command flakes' flake check -build: - nix --extra-experimental-features 'nix-command flakes' build .#darwinConfigurations.hari-macbook-pro.system +build config='hari-macbook-pro': + #!/usr/bin/env bash + if [[ "{{config}}" == "hari-macbook-pro" ]]; then + nix --extra-experimental-features 'nix-command flakes' build path:.#darwinConfigurations.{{config}}.system + else + nix --extra-experimental-features 'nix-command flakes' run github:nix-community/home-manager -- build --flake path:.#{{config}} + fi -switch: - sudo env PATH="$PATH" nix --extra-experimental-features 'nix-command flakes' run github:LnL7/nix-darwin/master#darwin-rebuild -- switch --flake .#hari-macbook-pro +switch config='hari-macbook-pro': + #!/usr/bin/env bash + if [[ "{{config}}" == "hari-macbook-pro" ]]; then + sudo env PATH="$PATH" nix --extra-experimental-features 'nix-command flakes' run github:LnL7/nix-darwin/master#darwin-rebuild -- switch --flake path:.#{{config}} + else + nix --extra-experimental-features 'nix-command flakes' run github:nix-community/home-manager -- switch --flake path:.#{{config}} -b hm-bak + fi fmt: nix --extra-experimental-features 'nix-command flakes' fmt diff --git a/lib/package-sets.nix b/lib/package-sets.nix new file mode 100644 index 0000000..839bf4d --- /dev/null +++ b/lib/package-sets.nix @@ -0,0 +1,139 @@ +{ + inputs, + lib, + pkgs, +}: let + gwsPackage = + inputs.googleworkspace-cli.packages.${pkgs.stdenv.hostPlatform.system}.default; + claudePackage = + inputs.claudeCode.packages.${pkgs.stdenv.hostPlatform.system}.default; + + memex = pkgs.stdenvNoCC.mkDerivation rec { + pname = "memex"; + version = "0.3.1"; + + src = pkgs.fetchurl { + url = "https://github.com/nicosuave/memex/releases/download/v${version}/memex-${version}-macos-arm64.tar.gz"; + hash = "sha256-OIqT0xS+8vc0dQNi+YdDXLmN8V/7AT4Q/cnvbbhZ+3s="; + }; + + dontUnpack = true; + + installPhase = '' + tar -xzf "$src" + install -Dm755 memex "$out/bin/memex" + ''; + + meta = { + description = "Fast local history search for Claude and Codex logs"; + homepage = "https://github.com/nicosuave/memex"; + license = lib.licenses.mit; + mainProgram = "memex"; + platforms = lib.platforms.darwin; + }; + }; + + 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; [ + curl + fd + fzf + gnupg + go_1_26 + jq + just + nodejs_22 + python3 + ripgrep + rustup + tree + uv + wget + zoxide + ]; + + extras = + (with pkgs; [ + awscli2 + claudePackage + coreutils-prefixed + delta + diff-so-fancy + git-filter-repo + git-lfs + goose + google-cloud-sdk + gwsPackage + imagemagickBig + kind + kubectl + kubernetes-helm + lazygit + libpq + librsvg + llmfit + mise + minikube + ngrok + postgresql_17 + redis + tailscale + terraform + texliveFull + yt-dlp + ]) + ++ lib.optionals pkgs.stdenv.isDarwin [ + graphite + memex + worktrunk + ]; + + fonts = with pkgs; [ + jetbrains-mono + nerd-fonts.symbols-only + ]; +} diff --git a/modules/base.nix b/modules/base.nix index 915eb0d..8af1303 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -1,8 +1,12 @@ { + inputs, + lib, pkgs, username, ... -}: { +}: let + packageSets = import ../lib/package-sets.nix {inherit inputs lib pkgs;}; +in { nix.enable = true; nix.settings = { @@ -31,23 +35,7 @@ programs.zsh.enable = true; environment.shells = [pkgs.zsh]; - environment.systemPackages = with pkgs; [ - curl - fd - fzf - gnupg - go_1_26 - jq - just - nodejs_22 - python3 - ripgrep - rustup - tree - uv - wget - zoxide - ]; + environment.systemPackages = packageSets.core; environment.variables = { EDITOR = "nvim"; diff --git a/modules/packages.nix b/modules/packages.nix index 8cd689a..74a6cea 100644 --- a/modules/packages.nix +++ b/modules/packages.nix @@ -4,116 +4,8 @@ pkgs, ... }: let - gwsPackage = - inputs.googleworkspace-cli.packages.${pkgs.stdenv.hostPlatform.system}.default; - claudePackage = - inputs.claudeCode.packages.${pkgs.stdenv.hostPlatform.system}.default; - - memex = pkgs.stdenvNoCC.mkDerivation rec { - pname = "memex"; - version = "0.3.1"; - - src = pkgs.fetchurl { - url = "https://github.com/nicosuave/memex/releases/download/v${version}/memex-${version}-macos-arm64.tar.gz"; - hash = "sha256-OIqT0xS+8vc0dQNi+YdDXLmN8V/7AT4Q/cnvbbhZ+3s="; - }; - - dontUnpack = true; - - installPhase = '' - tar -xzf "$src" - install -Dm755 memex "$out/bin/memex" - ''; - - meta = { - description = "Fast local history search for Claude and Codex logs"; - homepage = "https://github.com/nicosuave/memex"; - license = lib.licenses.mit; - mainProgram = "memex"; - platforms = lib.platforms.darwin; - }; - }; - - 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; - }; - }; + packageSets = import ../lib/package-sets.nix {inherit inputs lib pkgs;}; in { - environment.systemPackages = with pkgs; [ - awscli2 - claudePackage - coreutils-prefixed - delta - diff-so-fancy - git-filter-repo - git-lfs - goose - graphite - google-cloud-sdk - gwsPackage - kubernetes-helm - imagemagickBig - kind - kubectl - lazygit - libpq - librsvg - llmfit - memex - mise - minikube - ngrok - postgresql_17 - redis - tailscale - terraform - texliveFull - worktrunk - yt-dlp - ]; - - fonts.packages = with pkgs; [ - jetbrains-mono - nerd-fonts.symbols-only - ]; + environment.systemPackages = packageSets.extras; + fonts.packages = packageSets.fonts; }