Skip to main content

devenv integration

Jotain ships a native integration with devenv, the Nix-based developer environment tool. The library lives in lisp/devenv.el (standalone and reusable — no Jotain dependencies) and is wired in by init-devenv.el. Everything is driven through the devenv CLI and degrades to a clean error when the binary is not on PATH. devenv 2.1+ is recommended; every invocation sets AI_AGENT=1 so devenv’s TUI stays out of the machine-readable output.

Entry point: C-c v

C-c v (or M-x devenv) opens a transient covering the whole surface:
KeyCommandWhat it does
tdevenv-task-runPick a task (annotated from devenv tasks list --json) and run it; prefix arg selects the dependency mode (before/single/after/all)
sdevenv-script-runPick a script defined in devenv.nix (annotated with its description) and run it
Tdevenv-testdevenv test (enterTest, with processes started/stopped around it)
bdevenv-builddevenv build, optionally for specific attributes
u / ddevenv-up / devenv-downStart/stop the project’s processes; up streams into a live buffer (or detaches, see devenv-up-detached); prefix arg picks a subset
pdevenv-processesProcess dashboard (below)
ldevenv-processes-logsTail one process’s logs
i / / / :devenv-info / devenv-search / devenv-evalIntrospection: environment summary, package/option search, evaluate any config attribute to pretty-printed JSON
rdevenv-reloadRefresh the environment (below)
edevenv-env-global-modeToggle the native environment loader (below)
mdevenv-modeline-modeToggle the mode-line status segment (below)
a / xdevenv-allow / devenv-revokeTrust / untrust the project for auto-activation (below)
Mdevenv-mcp-setupRegister the project’s MCP server with mcp.el
U / Gdevenv-update / devenv-gcUpdate devenv.lock inputs / garbage-collect old generations
$devenv-show-logEvery CLI invocation is recorded in *devenv log*
The -c (--clean) and -r (--refresh-eval-cache) infixes apply to devenv-test and devenv-build. Long-running commands (test, build, tasks, update, gc) run in compilation buffers with Nix trace matching, so M-g M-n jumps to the file.nix:LINE:COL locations in evaluation errors.

Process dashboard

devenv-processes opens a tabulated view of the devenv process manager. Keys: s start, k stop, r restart, l/RET logs, u up, d down, g refresh. Data comes from devenv processes list (JSON when available, plain table on older devenv), fetched asynchronously so the UI never blocks.

Environment loading and reload

Environment loading stays with envrc + direnv (see init-prog): .envrc says use devenv, so every project buffer already carries the devenv shell environment buffer-locally — eglot servers, apheleia formatters, M-x compile, and the ghostel terminal all see devenv-provided tools with no extra configuration. After changing devenv.nix, run devenv-reload (C-c v r). It invalidates the library’s caches, refreshes the environment through envrc-reload-all, and — because eglot snapshots the environment when a server starts — offers to eglot-reconnect every server serving the project so language servers pick up new PATH entries. For devenv projects without direnv, devenv-env-global-mode is an optional native loader: it fetches devenv print-dev-env --json asynchronously and applies it buffer-locally, envrc-style. Its predicate skips any project with a .envrc, so it can never double-manage a buffer envrc owns. While a fetch is in flight, eglot-ensure is deferred and replayed once the environment lands, so language servers never start with the wrong PATH.

Auto-activation trust (devenv allow / revoke)

devenv 2.1+ gates shell auto-activation behind a per-project trust database (~/.local/share/devenv/allowed), managed with devenv allow and devenv revoke. The integration honours the same contract: the native loader (devenv-env-global-mode) consults the internal devenv hook-should-activate check and never evaluates an untrusted devenv.nix automatically — exactly like the zsh/fish/nu shell hooks. devenv-allow (C-c v a) trusts the project and immediately activates the loader in its buffers; devenv-revoke (C-c v x) untrusts it and drops the native environment. On devenv versions without the trust model (< 2.1) the loader behaves as before. Note that the direnv/envrc path has its own consent gate (envrc-allowdirenv allow), independent of devenv’s database.

Mode-line status

devenv-modeline-mode (global, enabled by init-devenv at startup) adds a status segment to the mode line for buffers inside a devenv project:
  • devenv[on] — the buffer’s environment carries the devenv shell (loaded by envrc/direnv or the native loader; detected via DEVENV_PROFILE).
  • devenv[off] — devenv project, environment not loaded.
  • devenv[!] — auto-activation trust denied; run devenv-allow.
Outside devenv projects the segment is empty. mouse-1 on the segment opens the devenv transient. The redisplay path is subprocess-free: trust is probed once per project in the background from find-file-hook and cached.

LSP for devenv.nix

devenv 2.0+ ships devenv lsp, a bundled nixd preconfigured with the project’s devenv module options (completion, hover docs for devenv.nix options). init-devenv routes devenv.nix and devenv.local.nix buffers to it while nil keeps serving every other Nix file — the routing entry delegates non-devenv buffers to whatever contact was registered before it.

MCP server for the AI stack

devenv 2.0+ ships devenv mcp, a stdio MCP server exposing nixpkgs package search, devenv option search, and process control (list/status/logs/start/stop/restart). devenv-mcp-setup (C-c v M) registers it with mcp.el under a per-project name (devenv-<project>); start it from M-x mcp-hub and run M-x gptel-mcp-connect to hand its tools to gptel. devenv-mcp-remove unregisters it.

Customization

The devenv customization group covers the executable name (devenv-executable), the quiet-mode environment (devenv-extra-env), global CLI flags (devenv-global-arguments), cache TTL and command timeout, detached up (devenv-up-detached), variables the native loader never applies (devenv-env-ignored-variables), and the dashboard’s log line count (devenv-processes-log-lines).
Last modified on July 9, 2026