Skip to main content

Packages

Jotain is a “use-package + Nix” configuration: Nix (or, in development, the devenv shell) provides most packages on load-path, so use-package finds them without touching the network; anything Nix does not ship falls through to MELPA at install time.

Provenance

  • Built-in to Emacs 30+ — always opt out of installation with :ensure nil.
  • Provided by Nix — built through emacsPackagesFor in devenv.nix (e.g. claude-code-ide, combobulate, the tree-sitter grammars). These also use :ensure nil because Nix already put them on the load path.
  • MELPA / NonGNU ELPA fallback — every other use-package block. use-package-always-ensure is t (set in early-init.el), so these default to “install if missing” without any extra boilerplate. Archives are registered in init.el:
    (add-to-list 'package-archives '("melpa"        . "https://melpa.org/packages/")        t)
    (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
    (add-to-list 'package-archives '("nongnu"       . "https://elpa.nongnu.org/nongnu/")    t)
    

Tree-sitter grammars

When built with default.nix (the full distribution — just build and friends), Jotain ships every tree-sitter grammar in nixpkgs via emacsPackagesFor emacs |> withPackages (epkgs: [ epkgs.treesit-grammars.with-all-grammars ]). The grammar bundle is exposed through TREE_SITTER_DIR; early-init.el picks that up and adds it to treesit-extra-load-path so every built-in *-ts-mode finds its grammar out of the box.

Packages that live in Nix

devenv.nix defines a small set of Elisp packages that are not on any archive (MELPA, GNU ELPA, NonGNU ELPA), so Nix builds them directly and puts them on load-path:
  • claude-code-ide — fetched from manzaltu/claude-code-ide.el, built with websocket and web-server as runtime dependencies (transient is built in to Emacs 30+).
  • combobulate — fetched from mickeynp/combobulate; all its dependencies (seq, map, treesit) are built in to Emacs 30+.
Both are consumed by use-package ... :ensure nil blocks in the relevant init-*.el module.

The devenv shell

Running inside devenv shell (or via direnv / .envrc) gives you the same Emacs that just build-bare produces, plus claude-code-ide, combobulate, and all tree-sitter grammars. devenv.nix enables the custom languages.emacs-lisp module (from nix/devenv-emacs-lisp.nix) which also provides eask-cli; ellsp (LSP) and elsa (static analyser) are off by default — toggle them in devenv.nix if you want them.

Adding a new package

Most of the time you just need a use-package block in the appropriate init-*.el module — :ensure t is implicit thanks to use-package-always-ensure:
(use-package some-package
  :mode "\\.ext\\'"
  :custom
  (some-package-option t)
  :config
  ;; configuration here
  )
If the package is not on any archive, add it to the overrideScope block in devenv.nix with trivialBuild so it is built from a pinned GitHub revision and available on load-path, then declare it with :ensure nil in the module.
Last modified on April 8, 2026