setup-devenv ยท diff
git:20260408.a08708c to git:20260422.18125cf
41 added, 42 removed. Audit A to A.
---
name: setup-devenv
- description: 13 composable Nix development shells for reproducible tooling. Use when setting up dev environments, configuring .envrc files, or adding Nix shells to projects.
+ description: Per-language toolchain + direnv guidance. Use when setting up a project's dev environment, configuring .envrc files, or choosing between version managers.
allowed-tools: Read Grep Glob Bash Edit Write
metadata:
- title: Nix Dev Shells
+ title: Per-Language Dev Environments
category: cli
order: 0
---
- # Nix Dev Shells
+ # Per-Language Dev Environments
- ## Overview
+ ## Philosophy
- All development environments are managed through Nix Flakes, providing reproducible, composable toolsets per language. Enter any shell with:
+ System-installed CLIs (git, gh, fzf, jq, kubectl, terraform, ...) come from Homebrew on macOS or apt/dnf/pacman on Linux. Per-language runtime versions come from the best-in-class tool for that language. No polyglot abstraction layer.
- ```bash
- nix develop .#<shell>
- ```
+ ## Runtime version managers
- ## Available Shells
+ | Language | Tool | Project pin | Notes |
+ |----------|------|-------------|-------|
+ | Node | [fnm](https://github.com/Schniz/fnm) | `.nvmrc` | `eval "$(fnm env --use-on-cd)"` in shell rc auto-switches |
+ | Python | [uv](https://docs.astral.sh/uv/) | `.python-version` + `pyproject.toml` | `uv venv` + `uv sync` |
+ | Rust | [rustup](https://rustup.rs) | `rust-toolchain.toml` | Auto-installs the pinned channel |
+ | Go | system `go` | `go.mod` go directive | One toolchain per machine usually fine |
+ | Lua | system `lua` | n/a | Pin via Brewfile/apt |
- | Shell | Purpose |
- |-------|---------|
- | `default` | Base tools only |
- | `node` | Node.js 22, npm/yarn/pnpm |
- | `python` | Python 3.12, uv |
- | `rust` | Rust stable, cargo, clippy |
- | `go` | Go, golangci-lint |
- | `devops` | Terraform, kubectl, Helm, k9s, AWS CLI 2 |
- | `lua` | Lua 5.4, luarocks, stylua |
- | `haskell` | GHC, cabal, stack |
- | `ruby` | Ruby, bundler |
- | `scheme` | Guile Scheme |
- | `perl` | Perl with core modules |
- | `java` | Java 21, Gradle/Maven |
- | `full` | All of the above combined |
+ ## .envrc patterns (vanilla direnv, no nix-direnv)
- ## Base Tools (Every Shell)
+ The standard direnv idioms cover most needs:
- Every shell includes a common set of CLI tools:
+ ```bash
+ # Python: auto-create + activate .venv on cd
+ layout python
- - **git**, **gh** version control and GitHub CLI
- - **fzf** fuzzy finder
- - **ripgrep** fast search
- - **jq**, **yq** JSON/YAML processing
- - **just** command runner
- - **direnv** per-directory environment variables
- - **chezmoi** dotfile management
- - **tmux** terminal multiplexer
- - **tree-sitter** incremental parsing
- - **uv** Python package manager (available everywhere)
+ # Node with fnm: load .nvmrc-pinned version
+ use fnm
- ## Usage with direnv
+ # Add project-local bin/ to PATH
+ PATH_add bin
- Projects use `.envrc` files with `use flake .#<shell>` to automatically activate the correct Nix shell when entering the directory:
+ # Load KEY=VALUE pairs from .env
+ dotenv
- ```bash
- # .envrc
- use flake .#rust
+ # Inherit ~/.envrc (which sources ~/.envrc.local for personal defaults)
+ source_up
```
- Combined with direnv, this means the right tools are always available without manual shell activation.
+ See `~/.local/share/chezmoi/dot_envrc.project.example` for a working template.
+
+ ## When to add an upstream installer
+
+ Adopt a chezmoi `run_onchange_after_install-<tool>.sh.tmpl` script with a pinned version when:
+
+ - The tool ships security/auth fixes faster than distro repos can package them (gcloud, aws-cli)
+ - The vendor distributes only via their own installer with no version-arg support (Snowflake Cortex)
+ - Reproducibility across machines matters more than the convenience of `brew upgrade`
+
+ Mirror the structure of `run_onchange_after_install-cloud-clis.sh.tmpl` or `run_onchange_after_install-cortex.sh.tmpl`. Pin the version at the top in ALL_CAPS, install to `~/.local/share/<tool>/<version>/`, symlink into `~/.local/bin`.
+
+ ## When NOT to add a polyglot version manager
+
+ asdf / mise / rtx solve the problem of "I want one config to pin Node + Python + Go + Rust." If the per-language tools above already cover your needs without that abstraction, don't add it. Polyglot managers add another layer of indirection (shims, plugin updates, slower shell startup). Only adopt one when project pinning matters across enough languages to outweigh that cost.