claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[FEATURE REQUEST] `direnv` support

Open angerman opened this issue 6 months ago • 10 comments

I often use claude in a directory with a direnv setup, and let claude modify the configuration. However claude is not able to see the updated PATH and other environment variables when direnv is reloaded. It will even try to run direnv reload, and then wonder why the changes it made did not work.

Adding direnv support to claude would be great!

angerman avatar Jun 15 '25 11:06 angerman

I stumbled across this same problem. I've used aider which just inherits the shell that it was executed from and it works perfectly.

However I was able to make claude code eventually work. The trick is that claude seems to use your login shell, which on my system was set to zsh. Once I added the proper direnv hook it started to work as expected.

I've got a pretty complicated setup using nix + direnv together and that fixed it. Hopefully this helps anyone until proper shell inheritance is added.

thorsteinson-qualified avatar Jun 18 '25 22:06 thorsteinson-qualified

I'm using nix as well- what did your fix look like? Why did it have to end up being complicated?

I've got a pretty complicated setup using nix + direnv together and that fixed it.

evanlhatch avatar Jun 22 '25 21:06 evanlhatch

Claude seems to run every command in a new shell, so environment variables don't carry over between commands. I tested this with !export FOO=bar and then !echo $FOO. I'm on a mac with zsh.

My workaround was to put this in ~/.zshenv (I still have the regular hook in ~/.zshrc), it seems to work OK but it's gross and I'd like a better way:

# also need mkdir -p ~/.config/direnv
# touch ~/.config/direnv/direnv.toml
# because there is a bug that causes DIRENV_LOG_FORMAT to be ignore if the config
# file does not exist

if command -v direnv >/dev/null; then
  if [[ ! -z "$CLAUDECODE" ]]; then
    eval "$(direnv hook zsh)"
    eval "$(DIRENV_LOG_FORMAT= direnv export zsh)"  # Need to trigger "hook" manually
  fi
fi

bls avatar Jun 23 '25 13:06 bls

another problem is when direnv is used in a subfolder (for example in a monorepo): Bash(cd subfolder && command-managed-by-direnv) => command-managed-by-direnv will not be found (this might be similar to #2632)

jlgeering avatar Jun 29 '25 14:06 jlgeering

For those using bash, I needed to put the script in .bashrc

programs.bash = {
  enable = true;
  bashrcExtra = ''
    if command -v direnv >/dev/null 2>&1; then
      if [ -n "$CLAUDECODE" ]; then
        eval "$(direnv hook bash)"
        eval "$(DIRENV_LOG_FORMAT= direnv export bash)"
      fi
    fi
  '';
};

jarjee avatar Jul 18 '25 09:07 jarjee

Does $SHELL env var match the type of shell you're running? Setting SHELL helped for claude & fish+direnv+flake setup.

mknapik avatar Jul 23 '25 11:07 mknapik

I wish I wrote down claude-code version. Setting $SHELL does not work anymore.

mknapik avatar Jul 30 '25 09:07 mknapik

Adding specifically direnv reloading support is poor design - this could be fixed more generally by allowing a hook to modify shell commands before they are executed (eg. to add environment reloading commands, but there are also quite a few other use cases - I'd also like to eg. filter stdout/stderr).

For this particular problem, another workaround is just to quit claude and do a claude --resume (assuming you have direnv shell integration set up).

jaens avatar Aug 14 '25 10:08 jaens

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

github-actions[bot] avatar Dec 07 '25 10:12 github-actions[bot]

symlinked in /etc/profile.d/claude-direnv.sh

if command -v direnv >/dev/null 2>&1; then
  if [ -n "$CLAUDECODE" ]; then
    eval "$(DIRENV_LOG_FORMAT= direnv export bash)"
  fi
fi

works well enough for me now

pscheit avatar Dec 07 '25 10:12 pscheit