NixOS is a big fan of reproduceability -- indeed that's what i'm using it for. But then I go read READMEs that say to do things like say "hey just download the code here from github's master.tar.gz and use it unconditionally". Nuh-uh, no can-do, bad idea. I'm going to maintain versions in a single Nix module which can be imported and used and updated when necessary.
These are available under pkgs.lib.pkgVersions.
To update this document:
Call cce/update-nixpkgs-checkout to update nixpkgs and then possibly resolve merge conflicts myself.
M-o iwill callnix-update-branch-revsto fetch the latest revision for modules usingbuiltins.fetchGit.fn1This is required because I couldn't getnix-update-declsto update the revs of these without also populating asha256key which will not be valid in abuiltins.fetchGitinvocation. Both nix-community/emacs-overlay and home-manager are loaded in situations where there is no pre-existing nixpkgs to invoke, so they have to use this "impure" invocation.C-u M-o owill callnix-update-declsto update therevandsha256for the rest. Note the prefix argument which will forcenix-prefetch-gitto fetch the latest revisions of the default (or specified) branch.
To understand why/how read on:
This document contains Magic
To get the org-auto-tangle to work with the document I have had to be quite careful in how I construct it. I would like to be able to update all the refs on the page at once, by an affirmative user-action. The process for updating this file involves using modifications I've made of jweigley's nix-update-el and is simple to operate:
There is some scaffolding and nuance required to make this work in the tangle stage.
First of all, org-auto-tangle is smart enough to not execute Org Babel functions by default. It's imperative to customize help:org-auto-tangle-babel-safelist.
Consider nix-update-branch-revs. These are fetched using this code block referenced in the document as prefetch-git-rev, evaluated, and the results inserted in to versions.nix using noweb syntax . If this was evaluated every time I saved the document, the version of home-manager and emacs-overlay which are imported would change every time I save!
prefetch-git-revemacs-lisp source: :var REPO="" :var BRANCH="main"(require 's) (s-chomp (shell-command-to-string (format "curl -s https://api.github.com/repos/%s/branches/%s | jq .commit.sha" REPO BRANCH)))
This require's things which aren't a part of Emacs by default, so I have to modify my AUTO_TANGLE document keyword with a new feature to pass variables in to the async Emacs invocation, thus #+AUTO_TANGLE: vars:load-path. This is, unfortunately, much slower to load and thus tangle now.
You'll note that this prefetch-git-rev is an elisp function, why not just use a shell-script? well, org doesn't load ob-shell by default, and passing org-babel-load-languages in to the async function was not enough to get it to work. oh well. Luckily I don't need anything too special here.
And so we are quite careful in how this document is constructed. Consider the home-manager example. If (NAME) were attached to the inline org-babel CALL, this would update every save. So the results have to be named. The (invocation) looks like a function call but will actually use the cached value.
org source:#+CALL: prefetch-git-rev(REPO="nix-community/home-manager", BRANCH="master") #+NAME: prefetch-hm (ref:NAME) #+results: : "60c6bfe322944d04bb38e76b64effcbd01258824" #+begin_src nix :noweb-ref homeManager :noweb yes homeManager = _: builtins.fetchGit { url = "https://github.com/nix-community/home-manager.git"; rev = <<prefetch-hm()>> (ref:invocation) ; }; #+end_src
By structuring these invocations like this it is possible to write a function contained in my nix-update page which will iterate over all the call sections and update the builtins.fetchGit entities, and then update the revisions and sha256 of the rest of the document, and safely tangle the new values out on save. This is probably a useful pattern in developing Hypermedia in org-mode.
NEXT update my NixOS version pins and deploy
sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
nix source: :tangle ~/arroyo-nix/versions.nix :noweb yes{ ... }: { <<homeManager>> <<emacsOverlay>> <<plasmaManager>> <<poetry2nix>> <<microvm>> <<nixpkgs>> <<nixos-hardware>> <<nixgl>> <<mastodon>> # org libraries <<consult-org-roam>> # <<ox-rss>> <<org-fc>> <<delve>> <<tabfs>> <<cpmtools>> <<tuhc>> # pythons <<beetcamp>> <<bandcamp-dl>> <<mopidy-bandcamp>> <<jisho-api>> <<twitter-to-sqlite>> <<inaturalist-to-sqlite>> <<kwin-plugins>> <<ttrss>> }
Run elisp:(cce/update-nixpkgs-checkout) first
Right now I am running off a branch of nixpkgs which builds vsketch and vpype for my Plotter Art , so it's kind of a pain to update rather than simply checking out the nixpkgs-unstable branch.. Might have to elisp:(magit-status "/home/rrix/Code/nixpkgs") and resolve some merge conflicts... I should upstream these packages!!!
Update home-manager by hand
"0d02ec1d0a05f88ef9e74b516842900c41f0f2fe"
nix source: :noweb-ref homeManager :noweb yeshomeManager = _: builtins.fetchGit { url = "https://github.com/nix-community/home-manager.git"; allRefs = true; rev = <<prefetch-hm()>> ; };
Update emacs-overlay used in Arroyo Emacs by hand
"d620f2831e367850fb9310849db3049587151ad1"
emacsOverlaynix source: :noweb yesemacsOverlay = _: builtins.fetchGit { url = "https://github.com/nix-community/emacs-overlay/"; rev = <<prefetch-em()>> ; };
^ This is upstream; I also have a checkout which I can manage with elisp:(magit-status "~/Code/emacs-overlay"); I can move the #+NAME keyword on the above code segment to this one to build a local instance:
nix source:emacsOverlay = _: /home/rrix/Code/emacs-overlay;
Update plasma-manager by hand
"a524a6160e6df89f7673ba293cf7d78b559eb1a5"
nix source: :noweb-ref plasmaManager :noweb yesplasmaManager = _: builtins.fetchGit { url = "https://github.com/nix-community/plasma-manager.git"; allRefs = true; rev = <<prefetch-pm()>> ; };
Update poetry2nix overlay
"ce2369db77f45688172384bbeb962bc6c2ea6f94"
poetry2nixnix source: :noweb yespoetry2nix = _: builtins.fetchGit { url = "https://github.com/nix-community/poetry2nix/"; rev = <<prefetch-p2n()>> ; };
Update nixos-hardware overlay
"c775c2772ba56e906cbeb4e0b2db19079ef11ff7"
nixos-hardwarenix source: :noweb yesnixos-hardware = _: builtins.fetchGit { url = "https://github.com/nixos/nixos-hardware"; rev = <<prefetch-nixos-hardware()>> ; };
Update microvm
"239045c84aa62c2ce1349fa4c1ceae9eb6ce9e85"
nix source: :noweb-ref microvm :noweb yesmicrovm = _: builtins.fetchGit { url = "https://github.com/microvm-nix/microvm.nix"; allRefs = true; rev = <<prefetch-microvm()>> ; };
mastodon in Emacs ->
builds from https://codeberg.org/martianh/mastodon.el/commits/branch/main
nix source: :noweb-ref mastodonmastodon = { pkgs, ... }: pkgs.fetchgit { url = "https://codeberg.org/martianh/mastodon.el"; rev = "5bba23045efda9f63c36ac431bec8f318a55e76a"; sha256 = "1z8qwnc01d9hx5m1xj3acpdzllfh4rxmypzcr3jl4ipp6dybzbx6"; # date = "2026-04-06T10:56:35+02:00"; };
nixGL ->
nix source: :noweb-ref nixglnixGL = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "nix-community"; repo = "nixGL"; rev = "b6105297e6f0cd041670c3e8628394d4ee247ed5"; sha256 = "1zv3bshk0l4hfh1s7s3jzwjxl0nqqcvc4a3kydd3d4lgh7651d3x"; # date = "2025-11-02T14:41:20+01:00"; };
TabFS ->
nix source: :noweb-ref tabfstabfs-rev = "09d57f94b507f68ec5e16f53b1cc868fbaf6cceb"; tabfs-fetch = {pkgs, ...}: pkgs.fetchFromGitHub { owner = "osnr"; repo = "TabFS"; rev = "cdf0f2e2dc7dba28c8e82ddb6842a4efc63547b2"; sha256 = "1sjkwzzg46jpbbpm8zj87zamdlljcs26a8qjx5d1mcmcdbac0xq3"; # date = "2024-12-28T09:34:41-05:00"; };
consult-org-roam
nix source: :noweb-ref consult-org-roamconsult-org-roam-rev = "268f436858e1ea3b263782af466a54e4d603a7d2"; consult-org-roam = {pkgs, ...}: pkgs.fetchFromGitHub { owner = "jgru"; repo = "consult-org-roam"; rev = "781d9c1cfee8631bc125fa45bab92de320d3941e"; sha256 = "18gwyv6zbbh4kqf8g8gz2rdi4sihmv7z9cmlksyg5j41a2l6imjg"; # date = "2026-02-09T19:05:15+01:00"; };
Consult-omni
nix source: :noweb-ref delveconsult-omni = { version = "0.1"; commit = "04c61a1eff0a19f131ab92e9342f420972c3d5cf"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "armindarvish"; repo = "consult-omni"; rev = "bdcd5a065340dce9906ac5c5f359906d31877963"; sha256 = "166ni9pd0w6npz27m26cnyj74r2qqa2bmlrn8hy79k39cq98lqmy"; # date = "2025-12-03T23:20:49-08:00"; }; };
ox-rss
nix source: :noweb-ref ox-rssox-rss = rec { version = "20230407.0450"; rev = "d2964eca3614f84db85b498d065862a1e341868d"; url = "https://github.com/benedicthw/ox-rss"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "BenedictHW"; repo = "ox-rss"; rev = "d2964eca3614f84db85b498d065862a1e341868d"; sha256 = "0piycm3b2lz2a9zg4g8ldsrjnbfvqhmf3aibsivb1dlvhzylwm4h"; # date = "2023-04-07T23:07:30-04:00"; }; };
org-fc
nix source: :noweb-ref org-fcorg-fc = rec { rev = "f64b5336485a42be91cfe77850c02a41575f5984"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "l3kn"; repo = "org-fc"; rev = "fce1cb265445f9c08ecb6b524562115eba9ab7a6"; sha256 = "1734ilc9418anl7hs102s2k8lm2ymvy6dyzpwxmjcw2vxmr2n9gw"; # date = "2026-01-17T22:38:26+01:00"; }; };
Ement.el
nix source: :noweb-ref org-fcement = rec { rev = "8aea26acefd9e3eafa24db240e41aa9d41603586"; src = { pkgs, ... }: pkgs.fetchurl { url = "https://github.com/alphapapa/ement.el/archive/8aea26acefd9e3eafa24db240e41aa9d41603586.tar.gz"; sha256 = "1zs8j9zvwda029ld2lnqkw03i7zsibrdy68fpsz5ylw7czd6qfzi"; # date = "2026-04-11T15:06:58-0700"; }; };
cpmtools
nix source: :noweb-ref cpmtoolscpmtools = { version = "2.21"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "lipro-cpm4l"; repo = "cpmtools"; rev = "e534e20c15973a9559e981efb498a102020e5db7"; sha256 = "0klad0zpxsllqcrjqqmsjvhcbrw7pjnkksr4n84ma6gc3nxb984c"; # date = "2020-07-26T12:24:37+02:00"; }; };
beetcamp
nix source: :noweb-ref beetcampbeetcamp = { version = "unstable-2022-06-07"; src = { pkgs, ... }: pkgs.fetchFromGitHub { repo = "beetcamp"; owner = "snejus"; rev = "3a9648dec55e1b4ff09deac937c5f55e6ff9fdf8"; sha256 = "1hn8wp3k01k2wj5vyd7bhm2kwphvp0bjqz9vpd3s10hqi1knkvir"; # date = "2026-03-31T22:14:25+01:00"; }; };
Mopidy Bandcamp
nix source: :noweb-ref mopidy-bandcampmopidy-bandcamp = { version = "1.1.5"; src = { python3Packages, ... }: python3Packages.fetchPypi { version = "1.1.5"; pname = "Mopidy-Bandcamp"; sha256 = "012w2iw09skayskbswp5dak0mp5xf3p0ld90lxhh8rczw9q763y2"; }; };
delve
nix source: :noweb-ref delvedelve = { version = "0.9.3"; commit = "9a3e2675ef76865e9ffd95bb49ae1c8307cbfcc1"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "publicimageltd"; repo = "delve"; rev = "9f294f2f09730fbb715a5a30469ce0d15291a3d6"; sha256 = "1w6rgyj0k5m3g2fg2my7v1kzghbymcy07scrbfhpg7hvcnm65sjx"; # date = "2024-12-25T20:11:57+01:00"; }; };
jisho-api
nix source: :noweb-ref jisho-apijisho-api = { version = "0.1.8"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "pedroallenrevez"; repo = "jisho-api"; rev = "fbb69d47a96f8942635d6b7d070abff430a747fd"; sha256 = "11d8bj7h93vfi1j3jaavm9ds14gzffsl23l4rz7riaw85vb4ib3q"; # date = "2025-12-08T07:31:48Z"; }; };
iNaturalist to Sqlite
nix source: :noweb-ref inaturalist-to-sqliteinaturalist-to-sqlite = { version = "0.2.1"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "dogsheep"; repo = "inaturalist-to-sqlite"; rev = "d888c7c2f02aa0dfb1559603f02357cd0089da11"; sha256 = "0iybdjinlxinsh4fk74k65q39rn1phwg0q9xjay9w90i74dqd0nr"; # date = "2020-10-21T17:08:29-07:00"; }; };
Twitter to Sqlite
nix source: :noweb-ref twitter-to-sqlitetwitter-to-sqlite = { version = "0.2.1"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "dogsheep"; repo = "twitter-to-sqlite"; rev = "f09d611782a8372cfb002792dfa727325afb4db6"; sha256 = "0nr2s1avb7ah7ygw5p75h0q6qsqvr97k46hi1hsc1j4w6gy2q810"; # date = "2021-12-26T10:08:40-08:00"; }; };
bandcamp-dl
nix source: :noweb-ref bandcamp-dlbandcamp-dl = { version = "0.0.1"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "iliana"; repo = "bandcamp-dl"; rev = "2334dbba00da874210191704b1e86ae489e543c0"; sha256 = "1h4jjrbgndsg2kg5hg0ar0m7bn1sb8b0chzp63pzqbyjsrr53lhm"; # date = "2023-12-26T23:03:05-08:00"; }; };
NEXT vsketch and vpype dependencies
NEXT automate fetchFromPyPi or move to GH fetchers
tt-rss plugins
nix source: :noweb-ref ttrsslarge_apod = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "joshp23"; repo = "TTRSS-APOD-Fix"; rev = "d6233f7a9031eaa07649d6b4777525524827f9de"; sha256 = "11vi81vha3sv9nq36ipxisrnrk5y38582f2nk7qg057d6jm9jw0f"; # date = "2017-06-25T13:52:41-04:00"; }; ttrss_wallabag = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "joshp23"; repo = "ttrss-to-wallabag-v2"; rev = "49ade5a1a216de74e42c4942ffa9cbf1bf426bec"; sha256 = "09rspawg0by5fk1x5b3b3smzqp4zw93h8c7zdxr63z6wjs41ba0j"; # date = "2021-03-14T01:26:43-05:00"; }; # https://gitlab.tt-rss.org/tt-rss/plugins/ttrss-af-readability ttrss_readability = { pkgs, ... }: pkgs.fetchgit { url = "https://gitlab.tt-rss.org/tt-rss/plugins/ttrss-af-readability"; rev = "fce528aa69c2a7193fb7eb3a3cd9dd17885d6ab6"; sha256 = "13z6rq9hc9j667qaqfdwlddzrccwp8q4a5s7gx1d169y2m1amnvv"; # date = "2025-10-16T16:16:47Z"; }; elfeed-sync = { rev = "7fb24f88f71f5e08208b75a001c50a6066a025af"; src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "SqrtMinusOne"; repo = "elfeed-sync"; rev = "7fb24f88f71f5e08208b75a001c50a6066a025af"; sha256 = "15gfvwa0dd4a0aqxazl0ncjrwzbqx0sjg9qm62fkyqjlfa8pspfa"; # date = "2023-12-26T02:15:46+03:00"; }; };
kde-base kwin etc plugins
nix source: :noweb-ref kwin-pluginskarousel = rec { src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "peterfajdiga"; repo = "karousel"; rev = "7d0e83ca2fc7e26e93ce8a5c418249cb433856aa"; sha256 = "0h9mwran1hyk3yawxrz9z9kggyp3v6gp437iram532ascv8x11q3"; # date = "2026-03-15T09:51:14+01:00"; }; version = "0.0.1"; }; kwin-force-blur = rec { src = { pkgs, ... }: pkgs.fetchFromGitHub { owner = "taj-ny"; repo = "kwin-effects-forceblur"; rev = "51a1d49d7fd7df3ce40ccf6ba4c4410cf6f510e1"; sha256 = "1kgqdzfrmavnjn8jm5w9hqcfsv9rwcx2mj3h82kkgv7n8xf7nlz8"; # date = "2025-08-13T17:29:55+02:00"; }; version = "1.3.2"; };