github cachix/devenv v2.2

5 hours ago

Bug Fixes

  • Fixed TUI commands continuing to run as CPU-spinning background processes after their terminal closed.
  • Fixed a potential stack overflow in devenv mcp while it indexed packages and options in the background. Indexing now runs with the large stack required by Nix evaluation and is interrupted when the server exits instead of delaying shutdown.
  • Fixed several failures in Cachix netrc setup: authenticated pulls could return HTTP 401, devenv could replace credentials in Nix's existing netrc-file, and caches could disappear as substituters when the managed netrc could not be prepared. devenv now installs credentials before opening the Nix store, merges them with Nix's existing netrc-file instead of replacing it, and keeps the cache available when a netrc file cannot be read or written. Generated credential files are private to the user and unique per process; stale files left behind by crashed or killed processes are removed.
  • Fixed SecretSpec providers such as SOPS being unavailable from the bundled CLI by enabling SecretSpec's default provider features.
  • Fixed the SecretSpec profile and provider selected in devenv.yaml being applied only during devenv.nix evaluation. devenv now exports the resolved values as SECRETSPEC_PROFILE and SECRETSPEC_PROVIDER in the development shell, so secretspec run and other SecretSpec commands use the same configuration. The matching secretspec CLI is also included in the devenv package instead of requiring a separate installation.
  • Fixed the Nushell hook failing to deactivate the environment when cd-ing out of a project. Nushell's exit cannot terminate a shell from an environment-change hook: it reported Exit doesn't catch internally and left the hook-spawned shell running. The hook now terminates that shell so the parent hook can resume and follow .devenv/exit-dir (#3033).
  • Fixed shell hooks skipping reactivation when returning immediately to a project after cd-ing out. The activation guard remained set after the parent hook followed the user out, so the environment only reactivated after leaving and returning a second time. The guard is now cleared for Bash, Zsh, Fish, and Nushell (#3034).
  • Fixed devenv tasks run hanging indefinitely when a task depended on a process with a ready probe (for example a task gated on services.mysql). The process started, but its readiness probe could not run, so the process never became ready and the dependent task waited indefinitely. The same configuration already worked under devenv up and devenv test (#3030).
  • Fixed a process crashing with "address already in use" when a second project reused a port still held by the first. After a project's detached process manager was stopped (devenv up -d then devenv processes down), its control socket could remain responsive briefly after its PID file was removed. A subsequent devenv up would then reuse stale port allocations instead of choosing a free port. devenv now reads running-manager port allocations only from a manager backed by a live PID file.
  • Fixed imports in devenv.yaml silently dropping a directory imported transitively through another project's devenv.yaml, rather than directly by the root project, when that directory had no devenv.yaml of its own. Its devenv.nix is now loaded regardless of the import depth.
  • Fixed editor-launched terminals and stripped environments defaulting to Bash when $SHELL is absent. devenv now checks the user's login shell from the system account database before defaulting to Bash, including under sudo and su. The shell's absolute path is used in both PTY and non-PTY interactive sessions, so it works even when $PATH does not contain its Nix store directory; stale login-shell paths fall back to the standard shell-resolution logic. devenv now also warns when an unsupported shell is explicitly requested via --shell or devenv.yaml before falling back to Bash (#2880, #2992).
  • Fixed the shell hook closing a pane or session in a terminal multiplexer such as tmux or zellij when leaving a project directory. Shells started from an active devenv shell, such as a new pane, an SSH session, or a manually started nested shell, inherited the hook marker and incorrectly treated themselves as hook-spawned. The marker is now consumed and removed from the environment as soon as the intended shell receives it, so it cannot leak to processes started afterward (#2861).
  • Fixed a hook-activated shell sometimes remaining active after leaving a project outside a terminal multiplexer. Deactivation depended on the spawned shell's rc file re-sourcing the hook script, which some configurations skip (for example, a Fish config gated behind status is-login, which a hook-spawned non-login fish -i never satisfies). Each shell's generated init file now handles leaving the project directly, independently of the user's rc file.
  • Fixed the Fish hook spawning a redundant devenv shell over an environment that direnv or another tool had already activated for the same directory via use devenv in .envrc. The hook decides whether to activate at one prompt and acts at the next to avoid spawning during cd, but it did not recheck whether another tool had activated the directory in the meantime.
  • Fixed cd - not returning to the project directory after the Fish hook followed the user out of it (#2853). The hook uses builtin cd to avoid retriggering a user-overridden cd (for example, zoxide init --cmd=cd), but this bypasses Fish's directory-history bookkeeping. The hook now updates that history itself.
  • Fixed input-relative imports (for example, imports: [myinput/some/dir]) being wrongly rejected with "Import path resolves outside the git repository" when a symlinked path was used to reach the project root, as occurs with macOS temporary directories under /var.
  • Fixed devenv shell appearing to hang in the TUI when the file watcher failed to register a watch, most commonly after reaching the inotify watch limit (fs.inotify.max_user_watches). The watcher now continues after a failed registration and surfaces a warning in the TUI instead of logging it only under --verbose --no-tui.
  • Fixed a task whose status command exits nonzero being rendered as a failed check status activity, making successful runs look like they contained a failure. A nonzero status is a normal cache miss that runs the task's command; only a failure to spawn the status command itself is now reported as a failure (#2984).
  • Fixed devenv processes restart leaving a restarted process reported as "exited" by devenv processes list/status even though it was running. When the process had previously exited (restart policy said stop), the restart spawned a fresh job and supervisor but never published a new status, and processes without readiness probes produce no further status events until they exit again. Restarting such a process now also replaces a supervisor parked after exit (kept alive only for file watching), which previously stopped monitoring the restarted job (#2982).
  • Fixed devenv overriding user-configured experimental features in nix.conf (#2931).
  • Fixed devenv hook bash/zsh skipping activation for a sibling project after following .devenv/exit-dir from a hook-spawned shell that left the previous project (#2944).
  • Fixed misleading evaluation errors where evaluation warnings replaced the real error message, hiding syntax errors and suggestions like devenv inputs add … (#2820).
  • Fixed devenv shell failing with Failed to parse output store path … is not in the Nix store when using a relocated or chrooted Nix store (e.g. NIX_REMOTE='local?root=…' or a bind-mounted store). The realized shell path was translated to its physical location and then fed back into store-path parsing, which only accepts the logical /nix/store/… form; the logical path is now recovered before creating the GC root (#2499).
  • Fixed the TUI crashing on activity names or store paths containing multibyte characters (e.g. non-ASCII package names or evaluation paths) when shortened for narrow terminals.
  • Fixed the TUI crashing with an arithmetic overflow when a download or task reported progress beyond its expected total.
  • Fixed the quit confirmation prompt overflowing past the right edge on terminals narrower than about 82 columns; the prompt now adapts to the available width.
  • Fixed the bottom navigation hint bar overflowing the right edge on standard 80-column terminals when a process was selected; the hints are now more compact on narrower terminals.
  • Fixed devenv invocations with different $TMPDIR values choosing different runtime directories and therefore failing to find each other's process manager. The runtime path now uses $XDG_RUNTIME_DIR, falling back to /tmp; $TMPDIR is no longer consulted. A daemon still using its previous runtime path may need to be restarted once (#2923).
  • Fixed edits to local path: inputs (e.g. url: path:../shared-config) never taking effect: the evaluation cache served the old configuration until .devenv was deleted, and devenv update did not help. Files from local path inputs are now read directly from disk and tracked by the cache, so changes apply on the next command and direnv reloads when they change.
  • Fixed the evaluation cache missing a devenv.local.nix (or any other tracked file) created within the same second as the previous evaluation, which could happen in scripts that run devenv commands back to back.
  • Fixed edits to enterShell causing a parse error (e.g. (eval):6: parse error near '\n') when a running devenv shell reloaded under Zsh or Fish. The enterShell output was being mixed into the environment data applied during reload; it now goes to the terminal as it does on a fresh shell entry (#2919).
  • Fixed devenv up (and other TUI commands) burning significant CPU while idle — roughly 10-15% per managed process — even when every process was quiet. The foreground UI was recomputing its layout dozens of times per second regardless of whether anything changed, and each idle process woke the whole UI twice a second. The TUI now only redraws when the model actually changes, with a slow heartbeat to keep elapsed timers ticking (#2915).
  • Fixed devenv container placing copyToRoot directories under a hash-prefixed subdirectory (e.g. /env/<hash>-source) instead of in the working directory. The project root and other directory paths now land directly under the working directory, and single files keep their original name (#2914).
  • Fixed local files and directories pulled into the Nix store by path (e.g. scripts.foo.exec = ./foo.sh; or languages.rust.import ./.) not being tracked as eval-cache dependencies, so editing them returned stale results from devenv build and devenv shell until the cache was manually refreshed. Such sources are now tracked, with directories hashed recursively over their contents so nested edits are detected (#2886, #2893).
  • Fixed devenv shell lingering as a background process, often pinned at 100%+ CPU, after its terminal window or tab was closed. The shell now reacts to the SIGHUP/SIGINT/SIGTERM that already trigger devenv's graceful shutdown by killing the inner shell, instead of orphaning it (#2845).
  • Fixed devenv shell/devenv update failing with authentication required but no callback set when a url."ssh://git@github.com/".insteadOf Git configuration rewrites GitHub HTTPS URLs to SSH. GitHub flake inputs now resolve over SSH using your SSH agent (#2842).
  • Fixed the "N files" counter under "Evaluating shell" inflating from generic Nix log lines. The counter now only includes actual file reads.
  • Fixed devenv up/test/tasks failing with error: could not find a flake.nix file when the devenv shell is loaded from a remote flake via direnv (#2599).
  • Fixed devenv shell printing internal reload warnings (e.g. "Watched path became unavailable, forcing reload") to the user's terminal, clobbering scrollback, prompts, and editors.
  • Fixed devenv up corrupting a running daemon's PID file and socket when started in the foreground, leaving the daemon unmanageable. Foreground up now rejects with "Processes already running" when a daemon is active.
  • Fixed a remaining case in which the shell hook spawned a nested devenv shell after devenv shell was entered manually (a follow-up to #2815).
  • Fixed "zoxide: infinite loop detected" when using zoxide init --cmd=cd fish and cd-ing into a devenv project. The Fish hook now defers spawning devenv shell to the next prompt instead of spawning inside the PWD event handler, so in-progress shell state never leaks into the devenv shell (#2841).
  • Fixed the Nushell hook behaving differently from the Bash, Zsh, and Fish hooks: outer shells with DEVENV_ROOT exported (e.g. via direnv) no longer exit when leaving the project, and a manually entered devenv shell no longer respawns a nested shell.
  • Fixed stale task and option results that lingered when devenv.nix was edited while a command was already evaluating. The eval cache no longer stores results whose tracked input files were modified mid-evaluation, so the next run sees the new definitions without deleting .devenv/nix-eval-cache.db* (#2745).
  • Fixed long lines in devenv shell getting a hard newline inserted at the wrap point when copied to the clipboard. The shell now preserves soft wrapping when flushing output into the terminal's scrollback, so clipboard copies keep the original single line (#2865).
  • Fixed files declared with the files option not being regenerated when an auto-loaded (devenv allow) shell reloaded after devenv update. enterShell tasks (including devenv:files) now rerun on hot reload, matching a fresh shell entry, instead of only updating environment variables (#2864).
  • Fixed devenv test --no-tui (and any other non-TUI invocation) silently discarding all output from the enterTest script, so the test runner's output, traces, and failure messages never reached the terminal or CI logs. Output from commands run in the shell is now printed in non-TUI mode.
  • Fixed watch paths being ignored for one-shot processes that exit immediately (e.g. code generators). The file watcher was torn down as soon as the process exited, so later edits never triggered a rerun. Watched one-shot processes now stay parked after exiting and rerun when a watched file changes.
  • Fixed devenv up intermittently failing to start processes with Failed to initialize task cache: … pool timed out while waiting for an open connection, most often in CI. Processes launched by a non-native process manager (e.g. process-compose) opened the same task-cache database concurrently and raced to create and migrate it; the database is now initialized once before the processes start (#2897).
  • Fixed devenv inputs add from a subdirectory writing to a stray devenv.yaml in the subdirectory instead of the enclosing project. It now walks up to find devenv.nix the same way devenv shell does, so the input is added where the rest of devenv reads it.
  • Fixed devenv gc failing with "File devenv.nix does not exist" when run outside of a project. Garbage collection operates on the global devenv store and no longer requires a devenv.nix (#2928).
  • Fixed unfree package errors suggesting only generic Nix/NixOS configuration. They now point devenv users to allow_unfree: true or nixpkgs.permitted_unfree_packages in devenv.yaml (#2850).
  • Fixed devenv shell failing outright with a SQLite disk I/O error on filesystems that don't support shared-memory mmap (seen on virtiofs/9p VM mounts and similar). The eval cache and task cache databases now fall back to plain rollback-journal mode on these filesystems instead of crashing (#2947).
  • Fixed failure diagnostics being buried in evaluation output in non-TUI mode. A failing evaluation no longer replays accumulated progress logs, such as evaluating file …, after the error, and devenv-run-tests now reports test failures after the diagnostic output instead of racing it.
  • Fixed lifecycle races in the native process manager: a process being relaunched could be started twice, leaving an orphaned copy that kept its port bound but no longer appeared in devenv processes list; a process whose dependency could not be satisfied vanished from the list instead of showing as stopped; and a relaunched process that had previously failed left its dependents permanently blocked on the stale failure.
  • Fixed devenv processes wait hanging forever when a process is waiting on a dependency that is stopped or not started.
  • Fixed devenv up -d silently scheduling processes into another terminal's foreground devenv up session; it now asks you to attach with plain devenv up or stop the session first.
  • Fixed devenv up attaching to a running process manager and then blocking, with no way to interrupt it, when run under an AI coding agent or with piped output. It now attaches only at an interactive terminal and otherwise reports that processes are already running.
  • Fixed devenv processes wait returning before a process was up while it was still waiting for a one-shot setup task (e.g. a migration); a running setup task now counts as in progress.
  • Fixed detaching from a running native process manager completing the attached process activities in the client TUI even though the daemon-owned processes were still alive. Attached rows are now non-owning proxies, and self-exited and crash-loop-exhausted processes retain distinct exited and gave up states.
  • Fixed two concurrent cold devenv up -d invocations racing to spawn separate native managers for the same project, which could orphan the losing daemon and its children. Daemon startup is now serialized until one manager publishes its PID, after which the other invocation attaches normally.
  • Fixed dynamically discovered process dependency closures remaining pending forever when an unseen one-shot failed or a shutdown cancelled it. Terminal failure and cancellation now propagate through the retained graph, and task cancellation reliably terminates the task's whole subprocess group.
  • Fixed a process that exited on its own and was then explicitly stopped still showing as exited (and counting as succeeded in run summaries) instead of stopped.
  • Fixed devenv up with no arguments not starting a process whose configuration omits start.enable, even though it defaults to enabled and devenv up <name> would start it.
  • Fixed a process that exits on its own (a crash or a one-shot that runs to completion with no restart) continuing to show as running in the devenv up TUI after it had stopped; it now shows as exited, while an exhausted crash loop shows as failed.

Improvements

  • devenv shell reload sessions now redraw only the terminal rows that changed instead of the whole screen every time output scrolls, reducing flicker and output bandwidth. Resizing the terminal mid-session no longer risks dropping pending lines from scrollback.
  • Reduced renderer fragmentation in devenv shell by reading PTY output in larger batches, lowering syscall and event-allocation overhead during full-screen repaint bursts.
  • DEVENV_HOME now overrides where devenv stores all per-user data (GC roots, trust database, cached keys), not just the trust database.
  • Non-TUI console output is now buffered and flushed in batches, reducing write overhead during verbose evaluation.
  • Traces now identify whether devenv was invoked by the CLI, direnv, or the native shell hook with a devenv.caller span attribute. Caller information is passed explicitly by integrations, so nested commands are not mistaken for automatic activation (#2965).
  • Reduced the size of the devenv closure and container image by about 550 MiB by linking nixd (used by devenv lsp) statically against LLVM, so the monolithic LLVM shared library is no longer bundled.
  • Reduced the size of the devenv binary's closure and container image by no longer bundling a debug build of libghostty-vt, which pulled Zig and LLVM (about 1 GiB) into every installation.
  • Added DEVENV_TRACE_DEFAULT_TO for configuring default trace destinations that apply only when no explicit --trace-to, DEVENV_TRACE_TO, or legacy trace output is set. Set DEVENV_TRACE_DEFAULT_TO to an empty string to suppress the default for a command or session (#2963).
  • Upgraded SecretSpec to 0.17.0, adding provider aliases, AWS Secrets Manager key prefixes, audit logging and access reasons, custom Bitwarden instances, and clearer provider-outage errors.
  • Cachix now authenticates pulls and pushes without exporting CACHIX_AUTH_TOKEN: set secretspec.cachix_auth_token to true (or a custom secret name) to enable a built-in required SecretSpec secret without a secretspec.toml declaration. If SecretSpec does not resolve a token, devenv falls back to the auth token stored by the Cachix CLI (cachix authtoken) in ~/.config/cachix/cachix.dhall. The resolved token is passed to the Cachix push daemon as well.
  • Added devenv tasks list --json for machine-readable task graph inspection (#2966).
  • devenv repl now exposes inputs alongside devenv and pkgs, so you can inspect inputs declared in devenv.yaml directly from the REPL (e.g. inputs.nixpkgs.lib.version).
  • The TUI now shows each process's state as a status dot whose shape encodes the lifecycle (waiting, starting, running, ready, stopped, failed) instead of an identical spinner on every process. The state remains recognizable without relying on color, while transient states gently pulse to signal progress.
  • Non-TUI console output now surfaces Nix evaluation and build progress while hiding internal debug noise.
  • Automatic TUI disabling and quiet output now use the detect-coding-agent crate, expanding detection beyond Claude Code to Aider, autonomous and cloud-based agents, and others. Set DEVENV_NO_AI_AGENT=1 to opt out.
  • Added devenv down as a shorthand for devenv processes down, mirroring devenv up (#2862).
  • devenv hook fish and devenv hook nu are now loaded automatically by Fish and Nushell via share/fish/vendor_conf.d/devenv.fish and share/nushell/vendor/autoload/devenv.nu, respectively. Bash and Zsh have no equivalent mechanism, so they still need manual configuration.
  • Added a --include-envrc flag to devenv init (also settable via DEVENV_INCLUDE_ENVRC) to scaffold a direnv .envrc file (#2859).
  • devenv --from <source> allow now binds a directory to an out-of-tree source, so you can use a devenv configuration without a local devenv.nix. Every subsequent devenv command in that directory loads its configuration from <source> without repeating --from, and the shell hook auto-activates the environment on cd just as it does for a local project.
  • --from path:<dir> sources now load their full configuration: the source's devenv.yaml (inputs and imports, including sibling imports within its git repository) is merged, and its modules are imported from the live directory so edits apply immediately without re-fetching.
  • devenv --from <source> --profile <name> allow also persists the selected profiles, so every subsequent command in the bound directory activates them automatically; explicit --profile flags still take priority.
  • devenv up now attaches to an already-running process manager (started by devenv up -d) instead of failing with "Processes already running". It streams status, ports, and logs over the control socket; honors the requested process subset (e.g. devenv up foo) and after/before ordering; and reports when it has attached. On Ctrl-C, it prompts you to detach and leave the processes running or stop the whole manager (#971).
  • Added devenv processes attach to attach to running processes and stream their status, ports, and logs until Ctrl-C, leaving them running (native process manager only).
  • devenv processes start <name> and devenv up <name> now share the same dependency-aware launch path. They honor after/before ordering; always start explicitly named processes, even with processes.<name>.start.enable = false; report unknown names with guidance; and register the full process set so other processes can be started later. When no manager is running, a named start launches one in the background, as with devenv up -d <name> (#2930).
  • Process port listings now include ports derived from listen readiness probes, not just explicitly declared ports, in both the TUI and devenv processes list.

Breaking Changes

  • Dropped x86_64-darwin (Intel macOS): devenv is no longer built, tested, or released for x86_64-darwin. Intel Mac users should pin an older devenv CLI release. x86_64-darwin environments can still be run via Rosetta 2 on Apple Silicon; however, nixpkgs 26.05 will be the last release supporting the platform.
  • Shell hook auto-activation: The shell hook (devenv hook bash/zsh/fish/nu) and devenv allow now detect a project by looking for devenv.nix instead of devenv.yaml. Projects with only a devenv.yaml and no devenv.nix will no longer auto-activate; add a devenv.nix to restore activation.
  • devenv init no longer creates .envrc by default: Pass --include-envrc or set DEVENV_INCLUDE_ENVRC to include the file (#2859).

Don't miss a new devenv release

NewReleases is sending notifications on new releases.