Files
mesh-catalog/modules/zsh/README.md
T
jochen cfe1dffa45
mesh/merge-gate pass: builds zsh → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group withhold-login-shell-execute delivered: every member is delivered
zsh: let a machine withhold node-login-shell's execute
execute runs any command as the operator account, which can become root
without a person. The operator withholds it on the control-node until a
call needs a person's approval (hq ADR 0268); the other machines keep it
for now. The setting execute (serve by default) is written into a
root-owned file the tools bundle reads at start, and anything but serve
withholds the verb, so the machine's runtime does not offer it.
2026-10-09 00:10:28 +02:00

5.3 KiB

zsh

The login shell as a module (novox/hq ADR 0176, ADR 0204, to-be 41).

  • Installs the zsh package and makes it the operator account's login shell through the user shape. The host gives the found shell back when the module goes.
  • Claims the mesh's node-login-shell seat and serves its verb execute: one command, run as the account in a zsh login shell in the account's home. It is ended with everything it started after 20 s by default (25 s at most, below the runtime's 30 s call limit). Each stream is cut at 256 KiB and the answer says so in truncated.
  • A machine may withhold execute (hq ADR 0268). It runs any command as the operator account, which can become root without a person. The setting execute is serve by default; a machine's layer withhold (mesh-controller.settings with module zsh, node the machine, values {"execute":"withhold"}, then a push) makes the runtime there offer no execute at all. The mesh writes the value into a root-owned tools.conf in the module's directory, which the tools bundle reads when the runtime starts it; a change restarts the runtime. Anything but serve (a wrong value, no file) withholds it, and says why on stderr and in zsh_config's execute. The control-node withholds it until a call to it needs a person's approval (hq research 039).
  • Its own tool zsh_config shows ~/.zshenv and ~/.zshrc as they are, with the mesh block's line count in each, and whether this machine serves execute, and why.
  • Contributes to the account's environment (ADR 0203): EDITOR and VISUAL (vim), XDG_CONFIG_HOME, and ~/.local/bin, ~/scripts, ~/scripts/bin at the start of PATH. The holder of node-environment (node-env) writes them; this module writes no export of its own.

The two blocks

Each block is the mesh's, between # BEGIN mesh zsh.<id> and # END mesh zsh.<id>. Every line outside a block is yours, kept byte for byte, and given back when the module goes.

  • ~/.zshenv, at the start: sources ~/.config/mesh/environment.sh if it is readable. Every zsh reads this file: a login, a script, and execute.
  • ~/.zshrc, at the start: the defaults every machine shares, with the three slots other modules fill (first, the defaults, normal, last). The defaults are the terminal title, seven keybindings, the colour aliases, ll/la/l, drun, disksize and sudo-disksize. Your lines below it run after it, so they win.

The one-off migration (ADR 0182)

The mesh removes nothing it did not make. After the first push that assigns this module, the lines below are in the block and in your own part of ~/.zshrc. Until you delete your copies, they run twice, which is harmless and visible. Deleting them is a person's act, once per machine.

Delete once zsh is assigned. The block or the environment now carries these:

  1. export EDITOR=vim
  2. export VISUAL=vim
  3. export XDG_CONFIG_HOME=$HOME/.config
  4. export PATH="$HOME/.local/bin:$HOME/scripts:$HOME/scripts/bin:$HOME/.dotnet:$PATH". Keep the one entry no module carries yet, as export PATH="$HOME/.dotnet:$PATH".
  5. The terminal title: function set_terminal_title() { … } and precmd_functions+=(set_terminal_title).
  6. The seven bindkey lines (Home twice, Ctrl+A, End twice, Ctrl+E, Del).
  7. alias drun='docker run -it --rm', and the functions disksize() { … } and sudo-disksize() { … }.
  8. The if [ -x /usr/bin/dircolors ]; then … fi block, with its aliases ls, dir, vdir, grep, fgrep and egrep.
  9. alias ll='ls -alhF', alias la='ls -Ah' and alias l='ls -CFh'.

Delete once powerlevel10k is assigned. Its contribution in the normal slot loads the prompt:

  1. #user_p10k_cache_file="${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${USER}.zsh", and the if [[ -r "$user_p10k_cache_file" ]]; then … fi after it. It does nothing today, because the variable is commented out.
  2. [[ ! -f ~/.zsh/themes/powerlevel10k/powerlevel10k.zsh-theme ]] || source …
  3. [[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh

Delete once zsh-autosuggestions / zsh-syntax-highlighting are assigned. Each module loads the distribution's copy from its own slot:

  1. [[ ! -f ~/.zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh ]] || source …
  2. [[ ! -f ~/.zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]] || source …

What stays yours. Keep these below the block until a module carries them:

  • the NVM_DIR lines;
  • MY_KV_PATH and MY_LIB_PATH;
  • CLAUDE_CODE_DISABLE_TERMINAL_TITLE;
  • the killport and findport aliases;
  • the zstyle lines;
  • the line sourcing ~/.zshrc.local, and that file itself.

Paths no longer used. The predecessor cloned these and nothing of the mesh reads them. Remove them by hand once the module that replaces each is assigned:

  • ~/.zsh/themes/powerlevel10k: replaced by powerlevel10k's pinned copy in ~/.local/share/powerlevel10k;
  • ~/.p10k.zsh: replaced by ~/.config/powerlevel10k/p10k.zsh, the same bytes, once powerlevel10k is assigned;
  • ~/.zsh/plugins/zsh-autosuggestions and ~/.zsh/plugins/zsh-syntax-highlighting: replaced by the distribution's packages;
  • ~/.zsh/plugins/zsh-autocomplete: loaded by nothing today.

Anything else under ~/.zsh/ is yours.