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
sourceis parse-time evaluated (no dynamic sourcing) - Fish syntax differs significantly from POSIX (no
$(), differentif, no[[) - Maintaining N copies of every alias/function is unsustainable
Decision¶
Adopt a hub-and-spoke bridge architecture:
- Hub: Canonical definitions live in
.chezmoitemplates/aliases/(Bash/POSIX) and.chezmoitemplates/functions/(Bash) - Bash/Zsh spoke: Direct inclusion via
90-ux-aliases.sh.tmpland50-logic-functions.sh.tmpl - Fish spoke: Runtime bash bridge with caching (
aliases.fish.tmpl,functions.fish.tmpl) - Nushell spoke: Hybrid approach:
- Aliases: Runtime bash extraction cached to
~/.cache/nushell/bash-aliases.nu(inenv.nu.tmpl), sourced byaliases.nu.tmpl - Functions: Chezmoi template-generated
defwrappers delegating to bash (infunctions.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_evalcaching - 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