Where is `shell.nix` documented? (or idiosyncrasies of Nix expressions used with shell-producing Nix commands)

By “shell producing Nix commands”, I mean these commands

  • nix-shell
  • nix shell
  • nix develop
  • (Are there other ways?)

I also understand that shell.nix itself is not documented as it is just a convention when the provided Nix expression is saved in a file (e.g., to be used with nix-shell).

What I’m alluding to are conventions such as

  • When are shellHook instructions run: after buildInputs are in scope or before?
  • To do shell string interpolation in the shell in shellHook, one has to use two single quotes to escape it because the Nix language uses the same convention.
  • defining shell / environment variables; for example, variables defined in mkShell's shellHook (without export) become shell variables, and variables defined outside it become environment variables (i.e., they get exported implicitly) in the resulting shell.
{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {

  shellHook = ''

  ENVIRONMENT_VARIABLE="the cake is a lie"

will produce

$ nix-shell -E "{pkgs ? import <nixpkgs> {} }: pkgs.mkShell { shellHook = ''SHELL_VARIABLE=27''; ENVIRONMENT_VARIABLE=\"the cake is a lie\"; }"

ENVIRONMENT_VARIABLE: the cake is a lie

[nix-shell:~]$ bash
ENVIRONMENT_VARIABLE: the cake is a lie

The above example is not a secret, one can figure it out from examples in the Nixpkgs manual, on nix.dev, in the NixOS wiki, etc., but this is never spelled out explicitly, so I wonder what other such Nix expression behaviours / features are there that I’m probably missing.

I also just realized while trying to find answers in the official docs that even individual packages can define their own Nix shell conventions. Case in point: Python’s postShellHook, preShellHook, venvHook.