envoluntary 0.1.4

Automatic Nix development environments for your shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# envoluntary

**Automatic Nix development environments for your shell.**

Envoluntary seamlessly loads and unloads Nix development environments based on
directory patterns, eliminating the need for per-project `.envrc` / `flake.nix`
files while giving you centralized control over your development tooling.

This bridges the gap between installing packages declaratively via NixOS /
home-manager and defining them for each project being worked in via `flake.nix`
/ direnv / nix-direnv. Especially useful when projects don't use Nix!

```mermaid
graph TD
    A["🌍 System-Wide Approach<br/>(NixOS/home-manager)"] -->|Pro: Centralized<br/>Con: Loses project specificity| B["Management Challenge"]
    C["📁 Per-Project Approach<br/>(flake.nix/direnv)"] -->|Pro: Project-specific<br/>Con: Setup burden| B
    B -->|Envoluntary Solution| D["✨ Pattern-Based Centralized<br/>(Best of both worlds)"]
    D --> E["✅ Centralized config<br/>✅ Project-aware<br/>✅ No per-project setup<br/>✅ Works for non-Nix projects"]
```

## Features

- **Pattern-based matching**: Define directory patterns once in your config, get
  automatic environment loading everywhere
- **Flake-native**: Built for Nix flakes from the ground up
- **Shell agnostic**: Works with bash, zsh, and fish
- **Fast caching**: Profiles are cached and only rebuilt when needed
- **Zero per-project setup**: No `.envrc` files to commit or maintain

## Quick Start

1. **Install**:

   ```bash
   cargo install envoluntary
   ```

   Or use via Nix shell

   ```bash
   nix shell github:dfrankland/envoluntary -c envoluntary --help
   ```

2. **Add the shell hook** to your `.bashrc`, `.zshrc`, or `config.fish`:

   ```bash
   # Bash/Zsh
   eval "$(envoluntary shell hook bash)"  # or zsh

   # Fish
   envoluntary shell hook fish | source
   ```

   Or use via Nix shell

   ```bash
   # Bash/Zsh
   eval "$(nix shell github:dfrankland/envoluntary -c envoluntary shell hook bash)"  # or zsh

   # Fish
   nix shell github:dfrankland/envoluntary -c envoluntary shell hook fish | source
   ```

3. **Configure your environments** in `~/.config/envoluntary/config.toml`:

   ```toml
   [[entries]]
   pattern = ".*/projects/my-website(/.*)?"
   flake_reference = "~/nix-dev-shells/nodejs"
   # Set whether the flake is impure
   impure = true

   [[entries]]
   # Patterns can match on tilde too
   pattern = "~/projects/rust-.*"
   flake_reference = "github:NixOS/templates/30a6f18?dir=rust"

   # Adjacent files or directories can be used to narrow pattern matches
   [[entries]]
   pattern = ".*"
   pattern_adjacent = ".*/Cargo\\.toml"
   flake_reference = "github:NixOS/templates/30a6f18?dir=rust"
   ```

4. **Navigate** to a matching directory and your environment loads automatically!

## Installing with Nix

The `envoluntary` flake exports a Nix overlay, making it easy to integrate into
your own Nix flake.

### About the Flake

The `flake.nix` in this repository is a [flake-parts](https://flake.parts/)
module that:

- Exports the `envoluntary` package as its `defaultPackage`
- Provides an overlay that makes `envoluntary` available in your own flakes

<details>
<summary><strong>Using the Overlay</strong></summary>

To use `envoluntary` in your own `flake.nix`, follow these steps:

#### 1. Add the input

Add `envoluntary` to your flake inputs:

```nix
{
  description = "Your flake description";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    envoluntary = {
      url = "github:dfrankland/envoluntary";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, envoluntary }:
    # ... rest of your flake
}
```

#### 2. Apply the overlay

Apply the overlay to your `pkgs`:

```nix
outputs = { self, nixpkgs, envoluntary }:
  let
    system = "x86_64-linux"; # or your system
    pkgs = import nixpkgs {
      inherit system;
      overlays = [ envoluntary.overlays.default ];
    };
  in {
    # Now pkgs.envoluntary is available
  }
```

#### 3. Use in your environment

You can now use `envoluntary` in your development shell or system configuration:

```nix
devShells.default = pkgs.mkShell {
  buildInputs = [ pkgs.envoluntary ];
};
```

</details>

<details>
<summary><strong>Using the home-manager Module</strong></summary>

The `envoluntary` flake exports a home-manager module for seamless integration
with your home configuration.

> **Note:** The overlay must be applied to your `pkgs` for this module to work.
> See the "Using the Overlay" section above.

#### 1. Add the input

Add `envoluntary` to your flake inputs (if not already added):

```nix
{
  description = "Your flake description";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    envoluntary = {
      url = "github:dfrankland/envoluntary";
      inputs.nixpkgs.follows = "nixpkgs";
      inputs.home-manager.follows = "home-manager";
    };
  };

  outputs = { self, nixpkgs, home-manager, envoluntary }:
    # ... rest of your flake
}
```

#### 2. Add the module to your home configuration

```nix
home-manager.sharedModules = [ envoluntary.homeModules.default ];
home-manager.users.your-username = {
  programs.envoluntary = {
    enable = true;

    # Optional: enable shell integration (all enabled by default)
    enableBashIntegration = true;
    enableZshIntegration = true;
    enableFishIntegration = true;

    # Optional: provide envoluntary configuration
    config = {
      entries = [
        {
          pattern = ".*/projects/my-website(/.*)?";
          flake_reference = "~/nix-dev-shells/nodejs";
          impure = true;
        }
        {
          pattern = "~/projects/rust-.*";
          flake_reference = "github:NixOS/templates/30a6f18?dir=rust";
        }
        {
          pattern = ".*";
          pattern_adjacent = ".*/Cargo\\.toml";
          flake_reference = "github:NixOS/templates/30a6f18?dir=rust";
        }
      ];
    };
  };
};
```

</details>

<details>
<summary><strong>Using the NixOS Module</strong></summary>

The `envoluntary` flake also exports a NixOS module for system-wide configuration.

> **Note:** The overlay must be applied to your `pkgs` for this module to work.
> See the "Using the Overlay" section above.

#### 1. Add the input

Add `envoluntary` to your flake inputs (if not already added):

```nix
{
  description = "Your flake description";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    envoluntary = {
      url = "github:dfrankland/envoluntary";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, envoluntary }:
    # ... rest of your flake
}
```

#### 2. Add the module to your system configuration

```nix
{
  imports = [
    envoluntary.nixosModules.default
  ];

  programs.envoluntary = {
    enable = true;

    # Optional: enable shell integration (all enabled by default)
    enableBashIntegration = true;
    enableZshIntegration = true;
    enableFishIntegration = true;

    # Whether to load envoluntary in nix-shell, nix shell, or nix develop
    # (default: true)
    loadInNixShell = true;

    # Envoluntary configuration
    config = {
      entries = [
        {
          pattern = ".*/projects/my-website(/.*)?";
          flake_reference = "~/nix-dev-shells/nodejs";
          impure = true;
        }
        {
          pattern = "~/projects/rust-.*";
          flake_reference = "github:NixOS/templates/30a6f18?dir=rust";
        }
        {
          pattern = ".*";
          pattern_adjacent = ".*/Cargo\\.toml";
          flake_reference = "github:NixOS/templates/30a6f18?dir=rust";
        }
      ];
    };
  };
}
```

</details>

## Configuration

### Adding entries

Manually edit your config file:

```bash
envoluntary config edit
```

Or add entries via the CLI:

```bash
envoluntary config add-entry ".*/my-project(/.*)?" ./path/to/flake
```

### Testing patterns

See which entries match a given path:

```bash
envoluntary config print-matching-entries /home/user/projects/homelab
```

### Flake references

Any valid Nix flake reference works:

- Paths: `~/my-flakes/devshell` or `/home/my-user/devshell`
- GitHub repos: `github:owner/repo` or `github:owner/repo/branch`
- Git repos: `git+https://example.com/repo.git`

See the [Nix flake reference documentation](https://nix.dev/manual/nix/latest/command-ref/new-cli/nix3-flake#flake-references) for more options.

## Advanced Usage

### Force profile updates

When your flake changes:

```bash
envoluntary shell export bash --force-update | source
```

Or just `cd` to a different directory and back—the hook will detect the stale cache.

### Override with explicit flakes

Test an environment without modifying your config:

```bash
envoluntary shell export bash --flake-references ~/test-flake | source
```

### Debugging

Check which Nix version you're using:

```bash
envoluntary shell check-nix-version
```

Inspect cache locations:

```bash
envoluntary shell print-cache-path --flake-reference ~/my-flake
```

View your config file path:

```bash
envoluntary config print-path
```

## Why should you use this?

### The problem

Many projects do not use Nix and adding `flake.nix` to each project can be bothersome.

Additionally, If you use NixOS or home-manager, your system packages are
declaratively managed. But when you need project-specific tools, you typically
reach for one of these solutions:

- **direnv + nix-direnv**: Requires a `.envrc` file in every project directory
- **Manual `nix develop`**: Forces you to remember to enter shells explicitly
- **Per-project flakes**: Scatters your development environment definitions
  across your filesystem

Each approach has drawbacks: `.envrc` files become noise in your repositories,
manual shells break your workflow, and scattered flakes make environment
management inconsistent.

### The solution

Envoluntary centralizes your development environment configuration while
maintaining automatic activation. Define your patterns once, and every matching
directory gets the right environment—no per-project files needed.

**Perfect for:**

- Maintaining consistent dev environments across multiple related projects
- Organizations with standardized tooling per project type
- Developers who want declarative control without repository clutter
- Anyone using NixOS/home-manager who wants the same philosophy for dev shells

**Not ideal for:**

- Projects where the environment definition should be version-controlled
  alongside code
- Shared repositories where other developers need easy access to the same environment
- One-off projects where you're fine with manual `nix develop`

## Prior Art

Envoluntary stands on the shoulders of giants:

### [direnv]https://github.com/direnv/direnv/

**Similarity**: Both tools automatically load environment variables when
entering directories.

**Difference**: direnv requires per-directory `.envrc` files and is language-
agnostic. Envoluntary uses centralized pattern-based config and is specifically
built for Nix flakes.

**Attribution**: All the shell integrations are adopted from direnv.

### [nix-direnv]https://github.com/nix-community/nix-direnv

**Similarity**: Both integrate Nix development shells with automatic directory-
based loading.

**Difference**: nix-direnv extends direnv to work efficiently with Nix, but
still requires `.envrc` files. Envoluntary eliminates per-directory
configuration entirely through pattern matching.

**Attribution**: All Nix dev env caching logic is based on nix-direnv's.

### [flake_env]https://git.sr.ht/~bryan_bennett/flake_env/

**Similarity**: Same similarities as nix-direnv, but flake_env is also portable.

**Difference**: Same differences as nix-direnv.

**Attribution**: Core concepts and some implementation patterns were adapted from
flake_env.

### [envy]https://github.com/mre/envy/

**Similarity**: Both use pattern-based matching to automatically load environments.

**Difference**: envy focuses on simple environment variable files, while
Envoluntary leverages the full power of Nix flakes for reproducible development environments.

**Attribution**: The pattern-matching approach and CLI structure drew
inspiration from envy's design.

## Contributing

Contributions welcome! Please open an issue or pull request.