anvil-pkg is a package manager you configure in Emacs Lisp, backed by the Nix store. It is a sub-system of anvil.el (the AI tool workbench), exposing package install / search / definition both as Elisp API and as Claude Code MCP tools.
The same idea as GNU Guix (Scheme over the Nix store) — but in Emacs Lisp, integrated with the anvil + NeLisp tool ecosystem so that AI agents can install anything by writing one Lisp form.
Phase 1+2+3 SHIPPED + REAL-NIX VERIFIED (2026-04-27) — Full DSL stack on top of the Nix store with multiple fetcher and build-system support.
- ERT 21/21 PASS (mocked, runs without a nix binary).
- Real-nix smoke test executed end-to-end in a
nixos/nix:2.34rootless podman container with Emacs 30.2:(pkg-install "hello")installed GNU Hello into an isolated profile and the binary ran.(pkg-list)reflected the install.(pkg-search "hello")returned 30 hits.(pkg-define) + (pkg-install 'sym)reached the Nix daemon through the generatedflake.nixand surfaced the expected hash-mismatch error from a placeholder.
- Generated
flake.nixvalidated by Nix as well-formed.
Public Elisp API uses the short pkg- prefix:
pkg-install/pkg-search/pkg-list— Phase 1pkg-definemacro — Phase 2github-fetch/git-fetchsources,rust/python/gobuild systems — Phase 3
Long-form aliases (anvil-pkg-install etc.) are provided via
defalias for Emacs-prefix purists.
Phase 4 (profile generation rollback + Nix 2.34’s
install=→=add deprecation follow-up) is the next milestone. Phase
4-A is also the current async-installer replacement candidate for
Nix-backed Emacs package installs;
see docs/design/02-dsl.org.
Claude Code (and similar agents) already speak anvil’s MCP tools
fluently. Adding anvil-pkg-install to that surface means an agent can
provision its own dependencies — install ripgrep, jq, language
servers, anything in nixpkgs — by emitting one Elisp form, without
shelling out to a different package manager per OS.
Nix already handles dependency closures, content-addressed storage,
sandboxed builds, and binary caches. anvil-pkg does not re-implement
any of that. It provides:
- An Elisp DSL (
anvil-pkg-define,anvil-pkg-install, …) that feels native to Emacs / NeLisp users. - A wrapper that translates that DSL to Nix expressions /
nix profilecommands. - A fallback path for Git-host packages not in nixpkgs (private
repos, in-development MCP servers), inspired by
async-installer.
Like async-installer, anvil-pkg prefers setq / defun /
anvil-pkg-define over a baroque use-package-style macro. Reading
your config should not require learning a new macro language.
┌─────────────────────────────────────────────────────────────┐
│ Elisp DSL │
│ (anvil-pkg-install "ripgrep") │
│ (anvil-pkg-define my-tool :src (github "...") :build ...) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ anvil-pkg core (this repo) │
│ - DSL parser / form → backend dispatch │
│ - manifest / generation tracking │
│ - MCP tool surface: anvil_pkg_install / search / list ... │
└─────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────┐ ┌─────────────────────────────┐
│ Nix backend (primary) │ │ Git backend (fallback) │
│ nix profile install ... │ │ inspired by async-installer│
│ nix-eval / flake / nixpkgs │ │ for non-nixpkgs repos │
└─────────────────────────────┘ └─────────────────────────────┘
| Phase | Scope | Status |
|---|---|---|
| 1 | nix profile shell-out wrapper. 3 MCP tools. install/search/list | SHIPPED |
| 2 | pkg-define DSL macro + flake.nix generation + symbol install | SHIPPED |
| 3 | github-fetch / git-fetch sources + rust / python / go bs | SHIPPED |
| 4 | Profile / generation management (rollback wrap) | next |
| 4-A | emacs-package build-system + post-install load-path | next |
| 5+ | Optional: independent package server, OS angle (research) | research |
See docs/design/01-overview.org for the full Phase 1 contract.
git clone https://github.com/zawatton/anvil-pkg ~/anvil-pkgIn your Emacs init:
(add-to-list 'load-path "~/anvil-pkg")
(require 'anvil-pkg)
(require 'anvil-pkg-dsl) ; Phase 2 — pkg-define macro
;; To register pkg-* MCP tools (requires anvil.el loaded):
(anvil-pkg-enable);; Phase 1 — install a package straight from nixpkgs
(pkg-install "ripgrep")
(pkg-search "rust")
(pkg-list)
;; Phase 2 — declare a custom package and install by symbol
(pkg-define my-rg
(version "13.0.0")
(source (url-fetch "https://github.com/BurntSushi/ripgrep/archive/13.0.0.tar.gz"
:sha256 "sha256-..."))
(build-system stdenv)
(inputs (list pkg-config openssl))
(install-phase "make install PREFIX=$out"))
(pkg-install 'my-rg) ; goes through generated flake.nix
;; Phase 3 — github-fetch + rust build-system
(pkg-define my-rust-tool
(version "1.0.0")
(source (github-fetch :owner "user" :repo "tool"
:rev "v1.0.0" :sha256 "sha256-..."))
(build-system (rust :cargo-sha256 "sha256-..."))
(inputs (list openssl)))
;; Phase 3 — git-fetch + go build-system (vendored deps)
(pkg-define my-go-tool
(version "0.3.0" )
(source (git-fetch :url "https://example.com/tool.git"
:rev "v0.3.0" :sha256 "sha256-..."))
(build-system (go))) ; vendorHash = null (vendored)
;; Phase 4-A — emacs-package build-system + post-install require
(pkg-define dash-test
(version "2.20.0")
(source (github-fetch :owner "magnars" :repo "dash.el"
:rev "2.20.0" :sha256 "sha256-..."))
(build-system emacs-package))
(pkg-install 'dash-test :require 'dash)CLI sub-command (anvil pkg install ...) lands in anvil.el via a
separate PR; until then call the Elisp API directly.
make test # 6 ERT tests, no nix binary required (all mocked)
make compile # byte-compile, warnings-as-errors- Emacs 29+ (anvil runtime requirement)
- Nix 2.18+ with flakes enabled (Phase 1 backend)
anvil.elloaded
anvil-pkg follows the existing anvil sub-module pattern (anvil-http,
anvil-state, anvil-defs, anvil-org-index, …). CLI is exposed as a
bin/anvil sub-command (anvil pkg install ...) so the user only ever
has one binary in $PATH.
If the project later outgrows anvil’s ecosystem, a standalone brand rename remains an option. Phase 1-3 do not require it.
GPL-3.0-or-later. Same as anvil.el and NeLisp.