--- description: "Use when modifying jsl-zsh, home-manager programs.zsh settings, or shell-tools wiring. Explains when to use wrapped jsl-zsh versus pkgs.zsh and how shell-tools composes into user and host configs." applyTo: 'modules/programs/zsh.nix, modules/features/shell-tools.nix, modules/users/**/*.nix, modules/nix-tools/user.nix, modules/services/ssh.nix, modules/hosts/**/*.nix' --- # jsl-zsh and shell-tools wiring This repo intentionally uses two zsh variants for different layers: - `pkgs.zsh` is the base system shell used for user login shell declarations. - `inputs.self.packages..jsl-zsh` is the wrapped interactive shell used by Home Manager and remote shell entrypoints. Treat these as distinct roles, not interchangeable defaults. ## Canonical definitions The canonical wrapped shell is defined in `modules/programs/zsh.nix`: - `perSystem.packages.jsl-zsh` wraps zsh via `wrapperModules.zsh.apply`. - Wrapper settings, aliases, history behavior, devenv hook, and extra package PATH come from this package definition. - `binName = "jsl-zsh"` is part of the external contract; keep it stable unless performing an explicit repo-wide rename. The Home Manager zsh module in the same file is the canonical consumer: - `flake.modules.homeManager.zsh` sets `programs.zsh.package` to `self.packages..jsl-zsh`. - Keep Home Manager interactive zsh bound to the wrapped package, not plain `pkgs.zsh`. ## shell-tools composition `modules/features/shell-tools.nix` is a composition module, not just a package list: - `flake.modules.homeManager.shell-tools` imports `homeManager.zsh` and `homeManager.files`. - It adds the wrapped `shell-tools` package to `home.packages`. - `home.shell.enableShellIntegration = true` is expected to stay with this module. If a user module imports `homeManager.shell-tools` (for example `modules/users/john.nix`), that user already receives the Home Manager zsh wiring transitively. ## System-layer expectations `modules/nix-tools/user.nix` keeps system login semantics separate from Home Manager interactive behavior: - `users.users..shell = pkgs.zsh` remains the login shell declaration. - `programs.zsh.enable = true` enables system zsh support. - `environment.shells` includes both `${lib.getExe pkgs.zsh}` and `${lib.getExe self.packages..jsl-zsh}` so wrapped shell paths are recognized when needed. Do not replace login shell declarations with `jsl-zsh` unless the task is explicitly changing system login policy. ## Host and SSH usage contracts Hosts may include `selfPkgs.jsl-zsh` in `environment.systemPackages` or `home.packages` so the wrapped shell is available directly. `modules/services/ssh.nix` includes host entries that use `RemoteCommand = "~/.nix-profile/bin/jsl-zsh"` (and commented variants). This path-level usage means: - keep the wrapper executable name stable (`jsl-zsh`), - update SSH remote command references in the same change if shell invocation paths are changed. ## Change guidelines When editing this area: - Keep wrapper behavior changes in `packages.jsl-zsh` focused and centralized. - Keep Home Manager zsh package selection pointed at wrapped `jsl-zsh`. - Keep system login shell semantics (`pkgs.zsh`) and interactive wrapper semantics (`jsl-zsh`) separated unless intentionally redesigning both layers. - If modifying `shell-tools`, verify it still composes zsh and tool packages for users importing the module. - If changing executable names or invocation paths, update all dependent consumers (including SSH remote commands and host package lists) in one coherent change.