From 104b8e2d8d23daec0903ebafa3cdeda825246f7e Mon Sep 17 00:00:00 2001 From: Fabian Ising Date: Mon, 3 Aug 2026 11:02:40 +0200 Subject: [PATCH] [ZSH] Venv for agents --- zsh/.virtual_env_config.zsh_mac.example | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/zsh/.virtual_env_config.zsh_mac.example b/zsh/.virtual_env_config.zsh_mac.example index c542367..24b0374 100644 --- a/zsh/.virtual_env_config.zsh_mac.example +++ b/zsh/.virtual_env_config.zsh_mac.example @@ -27,3 +27,49 @@ _venv_track_precmd() { } autoload -Uz add-zsh-hook add-zsh-hook precmd _venv_track_precmd + +# Which venv an agent shell should use: nearest .venv/venv walking up from $1 +# (default $PWD, stopping above $HOME), else the shared fallback env. +_agent_venv_path() { + local d=${1:-$PWD} c + while [[ $d == */* && $d != $HOME ]]; do + for c in "$d/.venv" "$d/venv"; do + [[ -f $c/bin/activate ]] && { print -r -- "$c"; return 0 } + done + d=${d%/*} + done + [[ -f $HOME/python-envs/claude/bin/activate ]] && print -r -- "$HOME/python-envs/claude" +} + +# Agent shells source this file once per session, rooted at the project dir, and +# snapshot the result: CLAUDECODE marks Claude Code, CODEX_SHELL the ChatGPT/Codex +# desktop app. Only VIRTUAL_ENV is set here; the block at the end of .zshrc turns it +# into an activation once PATH is fully built. Terminal launches use the wrappers below. +if [[ -n ${CLAUDECODE:-} || -n ${CODEX_SHELL:-} ]] && [[ -z ${VIRTUAL_ENV:-} ]]; then + _venv=$(_agent_venv_path) + [[ -n $_venv ]] && export VIRTUAL_ENV=$_venv + unset _venv +fi + +# Claude Code takes PATH from its own process env: its shell snapshot writes +# `export PATH=` last, discarding whatever .zshrc built. So the venv has to be +# active *before* launch. The subshell keeps this shell's PATH untouched. +claude() { + if [[ -n ${VIRTUAL_ENV:-} ]]; then + command claude "$@" + return + fi + local v=$(_agent_venv_path) + ( [[ -n $v ]] && source "$v/bin/activate"; exec command claude "$@" ) +} + +# Codex captures the profile's own PATH, so hand it VIRTUAL_ENV only and let the +# activation block at the end of .zshrc order PATH correctly. Pre-activating here +# would leave venv/bin behind gnubin and homebrew, same as tmux-inherited venvs. +codex() { + if [[ -n ${VIRTUAL_ENV:-} ]]; then + command codex "$@" + else + VIRTUAL_ENV=$(_agent_venv_path) command codex "$@" + fi +}