Summary

nixsh declares everything that lives in a terminal: shared environment and per-shell configuration (including fish universal variables and a guarded greeting) plus a terminal-native tool catalogue of shells, TUIs, CLI tools, and shell-integration hooks. Every binary is left to the system; the modules resolve each selection to the right package name per platform.

The core design rule is explicit: environment variables and PATH are shared and rendered per shell, while aliases, functions, and completions stay per shell because fish is not POSIX and a generic alias layer would render badly three times.

What it is

  • Shell modules: homeModules.nixsh, nixosModules.nixsh, and systemManagerModules.nixsh (see modules/home.nix, modules/nixos.nix, modules/arch.nix).
  • Policy and catalogue split: lib.policy with modules/nixsh.nix for shells, lib.toolsPolicy with modules/tools.nix for tools, backed by lib/shells.nix and lib/tools.nix data.
  • An underlay adoption pattern (absorbed from the earlier fish work) for typed per-shell extension of vendor-owned files, including fish universal-variable primitives.
  • Two source-backed packages: crow-cli (absent from normal sources) and termpdf (NixOS half of an AUR-only tool).
  • Declared checks: tool and underlay evaluation, systemd-user PATH projection, desktop-entry build, and Crow CLI legs, plus experiments/ and studies/ notes.

It has deliberately no per-host story: every host has a shell, unlike the display-substrate family.

How it works

One nixsh.environment declaration renders into fish’s set -gx form and into POSIX export form for bash and zsh. Greetings, login-shell assignment, rc files, and terminal selection compose on top. The tool catalogue resolves each nixsh.tools.selected entry into per-platform package names (NixOS, official-repository, AUR) with lean, integrate, and shell-hook dimensions, recording sources that exist on only one platform as explicit exceptions.

The underlay merges typed fragments into files the system or vendor already owns, with per-directory ordering documented in studies/. The systemd-user PATH projection carries a literal placeholder for the session manager to expand later; expanding it at Nix evaluation time would silently produce a wrong session PATH.

How to configure it

Compose the module for the target platform, then use the observed nixsh.* surface:

  • nixsh.environment.variables and nixsh.environment.path — the single shared declaration.
  • nixsh.fish, shell-specific aliases, functions, and interactiveInit — deliberately per shell.
  • nixsh.tools.<group> (core, integrate, nav, edit, git, system, network, data, media, archive, integrity, comms, record, misc) plus lean — catalogue selection by group; tools.selected and the per-platform package lists are internal read-only resolution results, not inputs.
  • nixsh.underlay* and greeting options — adoption of owned files and first-run presentation.

Review checks/tools-eval.nix, checks/underlay-eval.nix, and the studies/ naming notes (delta, micro, nvtop, p7zip, yq) before assuming a name resolves identically on both platforms.

Tutorial

This example uses invented values against the real option interface from the referenced revision. The interface shape below was evaluated with the actual homeModules.nixsh module at the pinned revision using synthetic values only; the resolved catalogue confirms the selection.

# Synthetic example: invented environment and tool choices.
{
  imports = [ inputs.nixsh.homeModules.nixsh ];
 
  nixsh = {
    environment.variables.EDITOR = "hx";
    environment.path = [ "/opt/tools/bin" ];
    tools.integrate = [ "starship" ];
  };
}

Selection happens through catalogue groups such as tools.integrate; tools.selected is an internal read-only view of the resolved entries, not an input. Per-shell content stays per shell by design:

# Synthetic example: public placeholder only.
nix run github:example-org/nixsh-demo#crow-cli -- --help

Treat catalogue names as platform-resolved selections to verify per host, not as literal package names.

Evidence and limits

This page is bound to public revision 7e71aa2c714a51a0603e25652625336ae414436c. That tree contains the flake outputs, modules/ host modules, lib/shells.nix, lib/tools.nix, packages/crow-cli.nix, packages/termpdf.nix, the checks/ suite, and the experiments/ plus studies/ material discussed above.

CNIX has not independently established a successful evaluation, shell render, tool resolution, or session result for that revision. The tutorial interface above was evaluated against the real module at that revision with synthetic values: environment settings pass type checking, the catalogue group accepts the selection, and the resolved entries confirm it. Catalogue coverage, underlay merge behavior, and greeting flows are described from source structure, not from reproduced runs.

nixsh owns terminal environment and tool selection only. Compositor setup, remote session forwarding, memory policy, file sharing, and tiny-VM server profiles are sibling concerns with their own revision-addressed concepts. Its relationship to other Corbet Nix projects is currently a shared design direction, not evidence of runtime integration.