From c72bd220d36f7905206beca359b9829e0ea8a14a Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 16 Mar 2026 15:14:15 +0100 Subject: [PATCH 1/5] use zsh as login shell on Linux, exec nu for interactive SSH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set thegeneralist-central's user shell to zsh (matching macOS pattern). Drop the isDarwin guard on .zshrc generation so all hosts get the SSH_TTY-gated nu exec — non-interactive SSH (Codex etc.) stays in zsh, real interactive sessions still land in nu. Co-Authored-By: Claude Sonnet 4.6 --- hosts/thegeneralist-central/configuration.nix | 2 +- modules/common/shell/default.nix | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hosts/thegeneralist-central/configuration.nix b/hosts/thegeneralist-central/configuration.nix index 4bec0ca..2360cc0 100644 --- a/hosts/thegeneralist-central/configuration.nix +++ b/hosts/thegeneralist-central/configuration.nix @@ -52,7 +52,7 @@ "scanner" "docker" ]; - shell = pkgs.nushell; + shell = pkgs.zsh; home = "/home/thegeneralist"; homeMode = "0750"; linger = true; diff --git a/modules/common/shell/default.nix b/modules/common/shell/default.nix index d3c37f7..bc4b6d2 100644 --- a/modules/common/shell/default.nix +++ b/modules/common/shell/default.nix @@ -11,7 +11,6 @@ let flatten getAttr mapAttrsToList - mkIf mkOption sortOn toInt @@ -64,7 +63,7 @@ in } ) - (mkIf config.isDarwin ( + ( homeArgs: let config' = homeArgs.config; @@ -72,15 +71,15 @@ in { home.file.".zshrc".text = # zsh '' - export PATH="/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/etc/profiles/per-user/$USER/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin''${PATH:+:}''${PATH}" + export PATH="$HOME/.local/bin:/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/etc/profiles/per-user/$USER/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin''${PATH:+:}''${PATH}" source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh - if [ -z "$INTELLIJ_ENVIRONMENT_READER" ] && [ -z "$skip" ]; then + if [ -z "$INTELLIJ_ENVIRONMENT_READER" ] && [ -z "$skip" ] && [ -n "$SSH_TTY" ]; then SHELL='${lib.getExe <| lib.head config'.shellsByPriority}' exec "$SHELL" fi ''; } - )) + ) ]; } From d2a025b164c75023e47761f8dd51164546915db5 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 16 Mar 2026 15:16:34 +0100 Subject: [PATCH 2/5] important changes --- hosts/thegeneralist-central/configuration.nix | 20 +++++++++---------- .../hardware-configuration.nix | 1 + modules/common/shell/0_nushell.nix | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/hosts/thegeneralist-central/configuration.nix b/hosts/thegeneralist-central/configuration.nix index 2360cc0..3e2bf46 100644 --- a/hosts/thegeneralist-central/configuration.nix +++ b/hosts/thegeneralist-central/configuration.nix @@ -94,20 +94,20 @@ openclawPkgs = let pkgsAarch64 = import inputs.nix-openclaw.inputs.nixpkgs { system = "aarch64-linux"; }; - steipetePkgs = - if inputs.nix-openclaw.inputs.nix-steipete-tools ? packages - && builtins.hasAttr - "aarch64-linux" - inputs.nix-openclaw.inputs.nix-steipete-tools.packages - then - inputs.nix-openclaw.inputs.nix-steipete-tools.packages.aarch64-linux - else - { }; + # steipetePkgs = + # if inputs.nix-openclaw.inputs.nix-steipete-tools ? packages + # && builtins.hasAttr + # "aarch64-linux" + # inputs.nix-openclaw.inputs.nix-steipete-tools.packages + # then + # inputs.nix-openclaw.inputs.nix-steipete-tools.packages.aarch64-linux + # else + # { }; in import "${inputs.nix-openclaw}/nix/packages" { pkgs = pkgsAarch64; sourceInfo = import "${inputs.nix-openclaw}/nix/sources/openclaw-source.nix"; - inherit steipetePkgs; + # inherit steipetePkgs; }; openclawPackage = openclawPkgs.openclaw; in diff --git a/hosts/thegeneralist-central/hardware-configuration.nix b/hosts/thegeneralist-central/hardware-configuration.nix index 070666c..1457e67 100644 --- a/hosts/thegeneralist-central/hardware-configuration.nix +++ b/hosts/thegeneralist-central/hardware-configuration.nix @@ -10,6 +10,7 @@ "sd_mod" ]; boot.initrd.kernelModules = [ ]; + boot.loader.systemd-boot.graceful = true; # Wi-Fi stuff nixpkgs.config.allowUnfree = true; diff --git a/modules/common/shell/0_nushell.nix b/modules/common/shell/0_nushell.nix index 01ad1b6..0d66161 100644 --- a/modules/common/shell/0_nushell.nix +++ b/modules/common/shell/0_nushell.nix @@ -20,7 +20,7 @@ let unstable = import (builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz"; - sha256 = if (config.onLinux) then "sha256:0fgmdh1j6qrx64wq8wk2hry2rjh3rkvz9pch29l8zn49nlndvxy2" else "sha256:16xi1yijq2ccbp8254zc0b5fgz0igxvyf4yn349wj2ggk4cl6dgn"; + sha256 = if (config.isServer) then "sha256:0fgmdh1j6qrx64wq8wk2hry2rjh3rkvz9pch29l8zn49nlndvxy2" else (if (config.onLinux) then "sha256:0fgmdh1j6qrx64wq8wk2hry2rjh3rkvz9pch29l8zn49nlndvxy2" else "sha256:16xi1yijq2ccbp8254zc0b5fgz0igxvyf4yn349wj2ggk4cl6dgn"); }) { system = pkgs.system; }; package = unstable.nushell; in From 20d43968874eb4040e24e0beb8aa9aefdd9a4e27 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:10:07 +0100 Subject: [PATCH 3/5] openclaw --- hosts/thegeneralist-central/configuration.nix | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/hosts/thegeneralist-central/configuration.nix b/hosts/thegeneralist-central/configuration.nix index 3e2bf46..460e70d 100644 --- a/hosts/thegeneralist-central/configuration.nix +++ b/hosts/thegeneralist-central/configuration.nix @@ -40,6 +40,7 @@ age.secrets.openclawGatewayEnv.owner = "thegeneralist"; age.secrets.openclawGatewayEnv.group = "users"; age.secrets.openclawGatewayEnv.mode = "0400"; + users.users = { thegeneralist = { isNormalUser = true; @@ -91,25 +92,31 @@ ... }: let + # openclaw's packages require fetchPnpmDeps and other tooling that is + # only present in its own pinned nixpkgs input, so we must build from + # there rather than from the host nixpkgs. openclawPkgs = let pkgsAarch64 = import inputs.nix-openclaw.inputs.nixpkgs { system = "aarch64-linux"; }; - # steipetePkgs = - # if inputs.nix-openclaw.inputs.nix-steipete-tools ? packages - # && builtins.hasAttr - # "aarch64-linux" - # inputs.nix-openclaw.inputs.nix-steipete-tools.packages - # then - # inputs.nix-openclaw.inputs.nix-steipete-tools.packages.aarch64-linux - # else - # { }; in import "${inputs.nix-openclaw}/nix/packages" { pkgs = pkgsAarch64; sourceInfo = import "${inputs.nix-openclaw}/nix/sources/openclaw-source.nix"; - # inherit steipetePkgs; }; - openclawPackage = openclawPkgs.openclaw; + + # openclaw bundles common CLI tools (rg, goplaces, …) directly in its + # /bin, which causes pkgs.buildEnv to abort with a "conflicting + # subpath" error when those tools are also in home.packages. + # + # Setting meta.priority = 10 (higher number = lower priority) tells + # buildEnv to silently prefer any other package that provides the same + # binary, instead of erroring out. Priority 5 is the nixpkgs default, + # so any explicitly installed package will win over openclaw's bundled + # copies while openclaw's own binaries (openclaw, openclaw-gateway, …) + # are still linked if nothing else claims them. + openclawPackage = openclawPkgs.openclaw.overrideAttrs (old: { + meta = (old.meta or { }) // { priority = 10; }; + }); in { home = { @@ -119,34 +126,39 @@ }; programs.openclaw = { - documents = ./openclaw-documents; - package = openclawPackage; - config = { - gateway = { - mode = "local"; - auth.mode = "token"; - }; - - channels.telegram = { - tokenFile = osConfig.age.secrets.openclawTelegramToken.path; - # Replace with your Telegram user ID from @userinfobot. - allowFrom = [ 0 ]; - groups."*" = { - requireMention = true; - }; - }; - }; - instances.default = { enable = true; package = openclawPackage; + + systemd.enable = true; + + config = { + gateway = { + mode = "local"; + auth.mode = "token"; + }; + + channels.telegram = { + tokenFile = osConfig.age.secrets.openclawTelegramToken.path; + # Placeholder overwritten at activation time by the script + # below, which reads the real ID from the age secret. + allowFrom = [ 0 ]; + groups."*" = { + requireMention = true; + }; + }; + }; }; }; + # Inject gateway credentials (ANTHROPIC_API_KEY, gateway token, …) + # from the age-encrypted env file into the systemd unit at runtime. systemd.user.services.openclaw-gateway.Service.EnvironmentFile = [ osConfig.age.secrets.openclawGatewayEnv.path ]; + # Patch the generated openclaw.json to replace the placeholder 0 above + # with the real Telegram user ID stored in the age secret. home.activation.openclawTelegramAllowFrom = lib.hm.dag.entryAfter [ "openclawConfigFiles" ] '' set -euo pipefail From 44b56d6fcf5ce4031e6602ad0c2a9479d2af6580 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:16:35 +0100 Subject: [PATCH 4/5] fix macOS local terminals not exec-ing nu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SSH_TTY guard was too broad — it broke local terminal sessions on macOS. Use platform-specific conditions: Darwin omits the SSH_TTY check (always exec nu unless IDE/skip), Linux keeps it (only exec nu for interactive SSH, leaving non-interactive sessions like Codex in zsh). Co-Authored-By: Claude Sonnet 4.6 --- modules/common/shell/default.nix | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/common/shell/default.nix b/modules/common/shell/default.nix index bc4b6d2..a6f4a5e 100644 --- a/modules/common/shell/default.nix +++ b/modules/common/shell/default.nix @@ -67,6 +67,11 @@ in homeArgs: let config' = homeArgs.config; + nuExecCondition = + if config.isDarwin then + ''[ -z "$INTELLIJ_ENVIRONMENT_READER" ] && [ -z "$skip" ]'' + else + ''[ -z "$INTELLIJ_ENVIRONMENT_READER" ] && [ -z "$skip" ] && [ -n "$SSH_TTY" ]''; in { home.file.".zshrc".text = # zsh @@ -74,7 +79,7 @@ in export PATH="$HOME/.local/bin:/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/etc/profiles/per-user/$USER/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin''${PATH:+:}''${PATH}" source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh - if [ -z "$INTELLIJ_ENVIRONMENT_READER" ] && [ -z "$skip" ] && [ -n "$SSH_TTY" ]; then + if ${nuExecCondition}; then SHELL='${lib.getExe <| lib.head config'.shellsByPriority}' exec "$SHELL" fi ''; From 6d5689d68a2dc6886db0f78530fbea3a0652c445 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:23:01 +0100 Subject: [PATCH 5/5] fix isServer --- modules/common/custom-options.nix | 2 +- modules/common/ghostty.nix | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/common/custom-options.nix b/modules/common/custom-options.nix index 9535eda..c55d401 100644 --- a/modules/common/custom-options.nix +++ b/modules/common/custom-options.nix @@ -16,7 +16,7 @@ in { isServer = mkOption { type = types.bool; - default = config.nixpkgs.hostPlatform.isAarch64; + default = config.nixpkgs.hostPlatform.isAarch64 && config.nixpkgs.hostPlatform.system == "aarch64-linux"; description = "Whether the system is a server. Determined by the processor architecture."; }; diff --git a/modules/common/ghostty.nix b/modules/common/ghostty.nix index afa847a..f6785bf 100644 --- a/modules/common/ghostty.nix +++ b/modules/common/ghostty.nix @@ -25,6 +25,7 @@ gtk-titlebar = false; mouse-hide-while-typing = true; + custom-shader = "~/.config/ghostty-shaders/shader.glsl"; }; }; }];