9 Packages

Jotain is a "use-package + Nix" configuration: Nix 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.

9.1 Provenance

9.2 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.

9.3 Packages that live in Nix

nix/extra-packages.nix defines the Elisp packages that are not on any archive (MELPA, GNU ELPA, NonGNU ELPA), so Nix builds them directly via trivialBuild from pinned revisions and puts them on load-path:

All are consumed by use-package ... :ensure nil blocks in the relevant init-*.el module and wired into the distribution by nix/mk-overlay.nix.

9.4 The devenv shell

The devenv shell provides tooling only — linters, language servers, the docs chain, fonts. Emacs itself is not in the shell (see the top-of-file note in devenv.nix); build and launch the editor with just run-built.

9.5 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 nix/extra-packages.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.

One invariant to know: the Nix side (nix/use-package.nix) parses the Elisp — it does not evaluate it. use-package forms must stay top-level (not wrapped in when/let/macros) and not :disabled, or the package silently drops out of the Nix-provided set even though the Elisp still works interactively.