Automatically generate and build a Nix derivation using an LLM.
mkAIDerivation is as simple as:
mkAIDerivation ''
Generate a derivation for building `xterm`
''This reaches out to an LLM over the network (currently using OpenAI),
generates the .nix code for this derivation, imports it, and builds it.
Now you can use Nix without worrying about annoying things like reproducibility or corretness!
This repo provides a couple different examples of using mkAIDerivation. You
can play around with this by first cloning this repo.
Once you have the repo, you'll need to run the ai-drv-server Python Flask
server. This is used to easily proxy connections to the OpenAI API (with
evil-nix being used to remove the
need for a hash).
You'll need an OpenAI API key available in the environment:
$ export OPENAI_API_KEY='sk-proj-vU...'And then you can run the server:
$ nix runOr, without Flakes:
$ nix-build ./nix -A ai-drv-server
$ ./result/bin/ai-drv-serverOnce the server is running, you can try out mkAIDerivation. There is an
example in the defaultPackage in flake.nix that is setup to generate a
derivation for sl (the funny program that
animates a train in your console when you mistype ls).
$ nix buildThis can take quite a while to build, since it has to query the OpenAI API to
generate a derivation, and then impurely fetch it with with
evil-nix.
If it succeeds, you can likely run the sl program with from the result:
$ ./result/bin/slCheck out the top of flake.nix to play around with this and try building other
programs.
There is also a default.nix to use this without flakes. Try running
nix-build for this. The default.nix also gives you a way to pass
a prompt for the derivation on the CLI:
$ nix-build --argstr msg 'Generate a derivation for building xterm'mkAIDerivation mainly works by using
evil-nix to (im)purely generate
some Nix code using an LLM over the network. And then just importing it and
building it using
Import From Derivation (IFD).
Here's a high-level overview of the steps:
-
First, you need
ai-drv-serverrunning to help with requests to the OpenAI API. This could in theory be a server running on the internet. I plan on working on this after getting a couple hundred million in VC money. For now, it is just something you have to run locally.By default,
ai-drv-serverruns onlocalhost:5000. -
Given a call to
mkAIDerivationlike the following:mkAIDerivation "generate derivation for xterm"
mkAIDerivationinternally usesevil-nixto make a request toai-drv-serverlike:GET http://localhost:5000/hash?req=generate+derivation+for+xtermUpon getting this request,
ai-drv-serversends a request to OpenAI to generate a derivation for this prompt. OpenAI returns something like:{ lib, stdenv, fetchurl, xorg, ncurses, freetype, fontconfig, pkg-config, makeWrapper }: stdenv.mkDerivation rec { pname = "xterm"; version = "390"; src = fetchurl { url = "https://invisible-mirror.net/archives/xterm/${pname}-${version}.tgz"; hash = "sha256-dRF8PMUXSgnEJe8QbmlATXL17wXgOl2gCq8VeS1vnA8="; }; ...
ai-drv-servercaches this derivation, then hashes it, and returns just the hash back tomkAIDerivation.Due to the way
evil-nixworks, many of the exact same request are sent to this/hashURL in order to download all the individual bits of the resulting hash. -
mkAIDerivationuses the hash returned in the previous step to download the the actual raw derivation text as a Fixed-Output Derivation (FOD).Imagine that the above request returned us a hash like
50+45s/yufGSJC5BIHYVmCsp1pAaJNBzyXYXSBUdSX8=.mkAIDerivationnow makes a FOD request toai-drv-serverusing this hash like:fetchurl { url = "http://localhost:5000/drv?hash=50%2B45s/yufGSJC5BIHYVmCsp1pAaJNBzyXYXSBUdSX8%3D"; sha256 = "sha256-50+45s/yufGSJC5BIHYVmCsp1pAaJNBzyXYXSBUdSX8="; }
The
ai-drv-serverreturns the raw derivation text it received from OpenAI. -
Finally,
mkAIDerivationinternally callscallPackageon the above raw derivation. -
The user crosses their fingers and hopes OpenAI didn't send them a derivation producing a binary that runs
rm -rf /.Oh well, YOLO!
-
Should all calls to
mkDerivationin Nixpkgs be replaced withmkAIDerivation?Yes.
I can't see how that would be a bad idea.
-
What are the downsides of using
mkAIDerivation?Your friends might think you're too cool and stop hanging out with you.
But that's okay, you can go kick it with your new friend Tom Cruise.
-
Does
mkAIDerivationreally require runningai-drv-server?ai-drv-servercould potentially just be some web application running on the internet. That would free you from having to run it locally. (There are some obvious questions about authentication and API keys that would have to be answered...)In theory, I think it would also be possible to write
mkAIDerivationwithout requiring a web server for proxying requests to OpenAI. In practice, this would be somewhat difficult due to howevil-nixworks.If someone figures this out, I'd be interested in seeing how you got it working.
-
How well does
mkAIDerivationwork in practice?It seems to work alright for really simple things that are already in Nixpkgs (like the
slandxtermexamples above).But my impression is that the popular LLMs aren't really that good at Nix yet. Your mileage may vary with anything more complicated.
-
How much engineering has gone into the system prompt sent to the OpenAI API?
Very little. There is probably a bunch of low-hanging fruit here.
-
Does this work with other LLMs, like Claude or Gemini?
In theory the
ai-drv-servercould be extended to work with other popular LLMs, but it currently only works with OpenAI. -
Could this work with local LLMs?
Probably? I haven't thought much about this.
In order to hack on mkAIDerivation (and ai-drv-server), you can get into the
development shell:
$ nix developOr, without Flakes:
$ nix-shellThis puts you in a shell with a python environment with all the transitive
dependencies needed by ai-drv-server.
You can confirm this by doing:
$ python
>>> import flask
>>> import openaiFrom this shell, you can easily run ai-drv-server with the following shell
script:
$ export OPENAI_API_KEY='sk-proj-vU...'
$ ./server/run-server.pyWith the server running, you should be able to build derivations using mkAIDerivation.
Or, you could access the server with curl:
$ curl -G --data-urlencode 'req=generate derivation for xterm' http://localhost:5000/hash
G9vctDWXtnjjswwmfkJs0msaAJFE+E55doJUCXEO6Fs=
$ curl -G --data-urlencode 'hash=G9vctDWXtnjjswwmfkJs0msaAJFE+E55doJUCXEO6Fs=' http://localhost:5000/drv
{ lib, stdenv, fetchurl, xorg, ncurses, freetype, fontconfig, pkg-config, makeWrapper, nixosTests, pkgsCross, gitUpdater, enableDecLocator ? true, }:
stdenv.mkDerivation rec {
pname = "xterm";
version = "388";
src = fetchurl {
url = "https://invisible-mirror.net/archives/xterm/${pname}-${version}.tgz";
hash = "sha256-rEKTReb5N6WUWonUJaJl/ubCFfxmnb3GoDJuIfTF9nQ=";
};
...You can also run ruff and pyright for linting, formatting, and type checking:
$ cd server/
$ ruff check # linting
$ ruff format # format python files
$ pyright # type checking