Direnv module stopped working; manual install works

What happened?

I had enabled direnv by uncommenting the direnv line in init.el. This resulted in direnv automatically activating relevant environments in Emacs buffers, and worked for a few years.

At some stage it stopped working.

In an attepmt to get direnv working again, I added (package! direnv) to packages.el and (after! direnv (direnv-mode)) to config.el, and direnv started working as expected[1].

Then I commented out the direnv line in init.el, and direnv continued to work[1].

[1] After doom sync

What did you expect to happen?

I expected direnv to continue working inside DOOM Emacs, as it had done before, without having to replace the direnv module with a manual installation and configuration.

Steps to reproduce

  1. Install direnv on the underlying OS
  2. Prepare a test environment:
    mkdir /tmp/debug-direnv
    cd    /tmp/debug-direnv
    echo export ABCDEFG=xxx > .envrc
    direnv allow
    
  3. Enable the DOOM Emacs direnv module by uncommenting it in init.el
  4. Enable eshell (or vterm) module.
  5. M-x eshell
  6. Check whether direnv works within Emacs (eshell, in this case):
    echo $ABCDEFG    # should give no output
    cd /tmp/debug-direnv
    echo $ABCDEFG    # should give: xxx
    

On My Machine ™ the ‘xxx’ fails to appear when using the direnv mobule, but it works fine when using a manually installed and configured direnv.

System information


Loading data dump...

Doom’s direnv module switched from the direnv.el package to envrc.el some years ago, so installing direnv.el is redundant.

That said, I couldn’t reproduce your issue the first time I tested (because I had export ABCDEFG=xxx in my test environment from the start), but when I removed it, the variable remained, making me realize that envrc caches the local environment. So you’ll need to do M-x envrc-reload or M-x envrc-reload-all if you intend to be updating your environments on the fly like that.

Otherwise, the module is working as intended. envrc.el is much more performant alternative to direnv.el (the latter affects Emacs’ global environment and executes any time you switch buffers, the former executes only once per directory and is cached for all buffers in that directory from that point forward).

Thank you for your reply and your time.

From what you wrote, I infer that the module was probably working, but the switch from direnv.el to envrc.el has changed the way the module works so that it no longer matches my expectations, which are that the environment of the current buffer should automatically match that of the most relevant .envrc, without the need for any manual intervention by the user.

IIUC, the new version of the module will require manual intervention, at least whenever the underlying environment changes. So If I want to keep the automatic behaviour, I should keep my manual installation of direnv.el.

I’m not sure how you came to that impression and would like to understand it (perhaps to fix or document it), but it is incorrect. The module (or envrc.el in this case) does not require any manual intervention to invoke direnv and change the environment of the current buffer. It does automatically, as direnv.el had. The difference is envrc only changes the environment in the current buffer when it is opened (or a cd X command executed in eshell), and direnv changes the global Emacs environment whenever you switch the focused buffer.

I can only imagine you are running into the cache. As mentioned, envrc caches the local environment in the buffer until you reopen the buffer, so if you plan to modify .envrc after opening the buffer, M-x envrc-reload or M-x envrc-reload-all is necessary.

I got the impression from these words:

I define dependencies for my projects in Nix flakes. Checking out older commits automatically updates the environment in the shell. It also used to update ‘on the fly’ in Emacs, when checking out a new commit with Magit. Then it stopped, but I got it back by disabling the module and installing direnv.el by hand.

So I guess that our misunderstanding is that you don’t expect me to be updating the environment ‘on the fly’, and that is exactly what I do.