Skip to content

ADR-007: Multi-Shell Parity Strategy

Status

Accepted

Date

2026-03-08

Context

The dotfiles distribution supports three shells: Zsh (default since macOS Catalina), Fish (modern interactive shell), and Nushell (structured data shell). The codebase has 98 alias files and 52+ functions written in POSIX/Bash. Without a parity strategy, each shell gets a fragmented subset of functionality.

Problem: Fish had zero access to the alias/function library until v0.2.501 added bridge templates. Nushell had only 6 hardcoded aliases and no function access.

Constraints:

  • Nushell's source is parse-time evaluated (no dynamic sourcing)
  • Fish syntax differs significantly from POSIX (no $(), different if, no [[)
  • Maintaining N copies of every alias/function is unsustainable

Decision

Adopt a hub-and-spoke bridge architecture:

  1. Hub: Canonical definitions live in .chezmoitemplates/aliases/ (Bash/POSIX) and .chezmoitemplates/functions/ (Bash)
  2. Bash/Zsh spoke: Direct inclusion via 90-ux-aliases.sh.tmpl and 50-logic-functions.sh.tmpl
  3. Fish spoke: Runtime bash bridge with caching (aliases.fish.tmpl, functions.fish.tmpl)
  4. Nushell spoke: Hybrid approach:
  5. Aliases: Runtime bash extraction cached to ~/.cache/nushell/bash-aliases.nu (in env.nu.tmpl), sourced by aliases.nu.tmpl
  6. Functions: Chezmoi template-generated def wrappers delegating to bash (in functions.nu.tmpl)

Parity tiers:

  • Tier 1 (Full): Zsh, Bash — all aliases, functions, lazy loading, cached eval
  • Tier 2 (Bridged): Fish — all simple aliases, all functions via wrappers, _cached_eval caching
  • Tier 3 (Compatible): Nushell — simple aliases (no complex bash syntax), all functions via bash delegation

Consequences

Positive

  • Single source of truth for aliases and functions
  • Adding a new alias/function automatically propagates to all shells
  • Nushell users get access to 40+ functions that were previously unavailable
  • Fish users get mtime-aware caching via _cached_eval

Negative

  • Complex bash aliases (pipes, conditionals) are skipped for Nushell
  • Function calls in Fish/Nushell incur bash subprocess overhead (~5ms per call)
  • Cache invalidation requires shell restart or manual cache clear

Risks

  • Nushell's rapid development may break bridge syntax in future versions
  • Very large alias sets may slow Nushell startup during cache generation