# ~/.zshrc # # A PLAIN FILE. Not a chezmoi template, deliberately. # # Templating this file is what broke sync-back: `chezmoi re-add` silently does # nothing on a .tmpl, so every edit made here had to be hand-copied into the # source or lost. Platform differences are handled at runtime below, by zsh, # which it is perfectly capable of doing. # # NO SECRETS LIVE HERE. Keys come from ~/.config/zsh/secrets.zsh, which is # generated from Bitwarden Secrets Manager, mode 600, and in no repository. # If that file is absent this shell still works — you just have no API keys. # ---------------------------------------------------------------- platform --- # Set before anything else; everything below branches on these instead of on # chezmoi template conditionals. typeset -g _mac=0 _lin=0 _wsl=0 _ubuntu=0 [[ $OSTYPE == darwin* ]] && _mac=1 [[ $OSTYPE == linux* ]] && _lin=1 [[ -n $WSL_DISTRO_NAME || -r /proc/sys/fs/binfmt_misc/WSLInterop ]] && _wsl=1 (( _lin )) && [[ -r /etc/os-release ]] && \ grep -qi '^ID=ubuntu' /etc/os-release && _ubuntu=1 # ----------------------------------------------------------------- secrets --- # One guarded source, and it is the only path by which a key enters this shell. # Regenerate with `dotsecrets`. Never edit by hand, never commit. [[ -r ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/secrets.zsh ]] && \ source ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/secrets.zsh # The bws token itself is a file, not a secret in this file. It is what lets # `bws` and `dotsecrets` run at all. [[ -r $HOME/.config/bitwarden/bws-token ]] && \ export BWS_ACCESS_TOKEN="$(<$HOME/.config/bitwarden/bws-token)" # --------------------------------------------------------- pre-prompt setup --- # Anything that must be set before the p10k instant prompt goes here. Nothing # in this section may write to stdout. export ZSH_AI_PROVIDER="gemini" export ZSH_AI_GEMINI_MODEL="gemini-2.5-flash" # Endpoint, not a credential — the matching key comes from secrets.zsh. export ZAI_BASE_URL="https://api.z.ai/api/anthropic" (( _ubuntu )) && { export GDK_BACKEND=wayland export QT_QPA_PLATFORM=wayland export CLUTTER_BACKEND=wayland export SDL_VIDEODRIVER=wayland } # Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc. # Initialization code that may require console input (password prompts, [y/n] # confirmations, etc.) must go above this block; everything else may go below. if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" fi # -------------------------------------------------------------------- PATH --- # `typeset -U` makes $path a unique-only array, so ordering is intentional and # duplicates are impossible — which is what the eight scattered appends and the # doubled ~/.local/bin used to produce. typeset -U path PATH _prepend() { [[ -d $1 ]] && path=("$1" $path) } _append() { [[ -d $1 ]] && path=($path "$1") } _prepend "$HOME/bin" _prepend "$HOME/.local/bin" _prepend "$HOME/.npm-global/bin" _prepend "$HOME/code/speccy/bin" _append /usr/local/bin _append /usr/local/go/bin export GOPATH="$HOME/go" export GOMODCACHE="$GOPATH/pkg/mod" _prepend "$GOPATH/bin" _append "$HOME/.cache/lm-studio/bin" (( _mac )) && { _prepend /opt/homebrew/bin _prepend /opt/homebrew/sbin _prepend /opt/homebrew/opt/hcxtools/bin [[ -n $BUN_INSTALL ]] && _prepend "$BUN_INSTALL/bin" export TERMINFO=/Applications/Ghostty.app/Contents/Resources/terminfo # Garmin Connect IQ SDK (tracks the SDK selected in current-sdk.cfg) _ciq="$HOME/Library/Application Support/Garmin/ConnectIQ/current-sdk.cfg" [[ -f $_ciq ]] && _append "$(<"$_ciq")bin" unset _ciq } (( _lin )) && { _append /usr/libexec/virtiofsd _append "$HOME/code/vp9enc-rs/target/release" } (( _ubuntu )) && export LD_LIBRARY_PATH="/opt/Qt-6.7.3/lib:$LD_LIBRARY_PATH" unfunction _prepend _append # ------------------------------------------------------------------ limits --- ulimit -n 65535 (( _mac )) && ulimit -u 2048 || ulimit -u 65535 # ------------------------------------------------------------------ oh-my-zsh - export ZSH="$HOME/.oh-my-zsh" export ZSH_CUSTOM="${ZSH_CUSTOM:-$ZSH/custom}" ZSH_THEME="powerlevel10k/powerlevel10k" plugins=(git zsh-autosuggestions sudo web-search dirhistory history) (( _mac )) && plugins+=(docker) # zsh-ai is loaded HERE and only here. It used to be added to this array on # every platform AND separately sourced from /opt/homebrew on macOS, so it # loaded twice on mac. The existence guard also stops the array referencing a # plugin that was never installed. [[ -z $ZSH_AI_DISABLE && -d $ZSH_CUSTOM/plugins/zsh-ai ]] && plugins+=(zsh-ai) # Guarded. Unguarded, a clean bootstrap produces a broken login shell and # nothing tells you why. if [[ -r $ZSH/oh-my-zsh.sh ]]; then source $ZSH/oh-my-zsh.sh else print -u2 "zshrc: oh-my-zsh missing at $ZSH — run dotup to install it" fi zle -N create_completion bindkey '^B' create_completion [[ -f ~/.p10k.zsh ]] && source ~/.p10k.zsh # ----------------------------------------------------------------- aliases --- (( _ubuntu )) && alias fd=fdfind (( _mac )) && { alias py="/opt/homebrew/opt/python@3.13/Frameworks/Python.framework/Versions/3.13/bin/python3" alias tailscale="/Applications/Tailscale.app/Contents/MacOS/Tailscale" } alias umpv="$HOME/code/mpv/TOOLS/umpv" (( _lin )) && { alias lada-runner="LADA_RUNNER_CONCURRENCY=2 uv --directory $HOME/tools/lada-runner run lada-runner tui" alias lada-cli="flatpak run --filesystem=host --command=lada-cli io.github.ladaapp.lada" } # Work Claude account — separate creds/history/projects, shared CLAUDE.md+rules+skills+agents alias wclaude='CLAUDE_CONFIG_DIR=$HOME/.claude-work claude' # A function, not an alias. As an alias the token was expanded into the alias # body at definition time, so `alias` printed the key in full to anyone who ran # it. A function defers expansion to call time. glm() { ANTHROPIC_BASE_URL="$ZAI_BASE_URL" ANTHROPIC_AUTH_TOKEN="$ZAI_API_KEY" \ claude --dangerously-skip-permissions \ --settings "$HOME/.claude/settings-glm.json" "$@" } _open() { (( _mac )) && open "$1" || xdg-open "$1" >/dev/null 2>&1 } # ------------------------------------------------------------------- local --- # Identity-bearing shell config -- the gitea aliases and their WAN/LAN hosts, # work shortcuts, anything naming a host you own -- lives in the PRIVATE tier, # which writes this file. It is absent on a public-only machine, and the guard # makes that a silent no-op. `_mac` and `_open` above are still in scope here, # so a moved alias needs no rewriting. [[ -r ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/local.zsh ]] && \ source ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/local.zsh # ---------------------------------------------------------------- homebrew --- if (( _mac )); then eval "$(/opt/homebrew/bin/brew shellenv 2>/dev/null || /usr/local/bin/brew shellenv)" elif [[ -x /home/linuxbrew/.linuxbrew/bin/brew ]]; then eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" fi # ---------------------------------------------------------------- bitwarden --- # Interactive personal-vault unlock. Nothing automated depends on this; the # unattended path is bws + the token file above. if command -v bw >/dev/null 2>&1; then bwunlock() { export BW_SESSION="$(bw unlock --raw)" print "Bitwarden unlocked. Session expires based on your timeout setting." } fi export ZSH_CODEX_PYTHON="$HOME/.local/venvs/codex/bin/python" # iris was removed here. Do NOT add `eval "$(iris init zsh)"` — it emits # `exec iris`, which replaces every interactive shell, and combined with the # p10k instant prompt above (upstream #55) logins fork-cascade until SSH # appears frozen. See the sysjournal note before reintroducing it. unset _mac _lin _wsl _ubuntu