 Can you hear me? Oh, I can hear you, can you hear me? Yeah, I can hear you too. Hey, how you doing? Good, how about you? Good, I'm all right. I'm the only person here so far, I guess. Drinking a potion, what's that? Oh, no, it's just water and a colored cup. Oh, okay, okay, okay. With your green necklace and the drink or something, I was like, oh, she's gonna cast a spell. Is it potion of insight plus five? The last four or two hours. That's what it takes to understand D-Haul. Is it doll or D-Haul? How do I pronounce it? Doll. Okay, I'm always saying D-Haul, so you'll have to forgive me, but if that's what it takes to figure it out, then I guess I'll drink some of the potion. Oh, we got our second guest. Hey there. Thanks for doing this. I might not stay for the whole time, depending on how many people show up and how guilty I feel, but it's midnight where I'm located, so. Yeah, I understand. Who I am. Oh, yeah. Happy to have you here, Lynn.pi. Looks like Sam has a question or, oh, maybe he's just waving. So how's everybody doing? I'm good, thanks. Dude, well. I think I've got my mic working. I'm doing good. I'm excited to learn about Knicks. Yeah, I'm also very stoked to learn about, you know, how we can use Knicks derivations. They're kind of confusing if you're just kind of getting into it. It's kind of like a giant, like, ramp up. It is. Like a learning curve, so. It's really nice to have someone explain it. Yeah, for me it was really hard to kind of break the pattern of like having loops, like looped data structures, have variables that I can assign and have loops, like none of that's available to me. You know, it's like I have these let-in blocks where I can create these temporary variables in scope and then there's width, which passes things implicitly and I don't know. So it's a bit of a paradigm shift. Yeah, for sure. And debugging tools are really primitive. So if something breaks, you should get like a nasty garbage print and then you don't know what broke. So have they not joined from the office that's linked to in-person votes? Yeah, I'm not sure what the plan was. Yeah, they should have joined by now. Let me see if I can get a hold of somebody. Yeah, nope. One thing that I really like about Nix is that, so I describe my whole operating system in Nix, I think a lot of people do this. And so I just have like a flake where I describe like how I want my OS to be configured and I have components for like different users on my system. And then I can like output to a virtual machine image if I wanna just run something in Kimu and I can take parts of it and like keep my shell and some of my configuration stuff, but not like all of my environment packages and then create like an EC2 image that I can deploy in the cloud and SH2 and have sort of like my similar environment. So it just makes the idea of what my operating system is kind of flexible and component-based. So I can like take off the arm and put it on something else and take off the head and put it on something else. And then I can just update the kernel super easily whenever I want to. I don't have to wait for Debian maintainers to ship something in six months. I can just change like an override and I don't know, it's pretty cool. So I have like different flake outputs for my different laptops and stuff with different like slightly different like hardware configuration stuff. And I don't know a few hundred lines of text and it's all there, it's pretty neat. And it makes, you know, it's kind of, it makes it's like the design makes sense. You know, you have like a dependency tree and things only change if like the source code actually changes not if like the hash of some comment like I deal with open embedded sometimes. I don't know if I've taken a bandwidth but real quick, I work with open embedded and open embedded is like a to build system written with like bash and Python scripts. And it determines if contents change based on like a hash of the file contents. So if you change even a comment then the hash will change it's got to rebuild the whole subtree. But with Nix it only analyzes the derivation source and that can still get a little nasty. Like if you add a comment to a bash script inside Nix it will still like invalidate the, the Shaw and like rebuild it or whatever but the NAR or whatever, I don't know, yeah. But I don't know, it's, the cache with Nix hits a lot more than with open embedded and it's a lot more, it's reproducible. So open embedded doesn't have that property. I'll build the same thing multiple times with open embedded and the, the hash of the result will change which is super annoying, right? You know, it'd be actually really nice if the, if something like write shell application from Nix packages with strip comments. So from Nix evaluation time so the hash would be unperturbed by them. Yeah. Yeah. It sounds tricky to like parse different scripting languages and remove their comments, but it would be really nice. Yeah. I mean, for bash, you can just do the dumb thing just filter out, you know, lines ending with, you know, hash. Starting with a hash or something. Yeah. But then if you have like an inline Python statement executed the bash like, you know, that's true. I mean, you can also just do like standalone. Oh yeah. Then you have here docs, I guess. So yeah, you're right. It would be a little interesting. Nix, Nix, it gets hard. Yeah, it gets hard. Best thing is just not to write bash. Right. All your source code in Nix. Yeah. Sometimes I'll like interpolate a Nix, I'll interpolate a Nix comment and then empty stream just to avoid perturbing the hash. Yeah. The cache. Yeah. Exactly. Yeah. Sorry to interrupt. So Claude had a, a conversation to attend. So he is not able to MC today. So I got assigned the role. David Lewis, I've been kind of volunteering to help with this, with this group for a while. We're currently hosted physically at the improving offices in Richmond on Richmond Avenue in Houston. We have openings if you're more standard programming during your day job. We're working on some more interesting stuff. And welcome to the functional program you used. Gabriela, thank you for speaking tonight. Got started a little bit late. You usually like to sign in a little early to kind of do a tech check, but we had some networking issues. My fault entirely. So I'm gonna hand this over to Gabriela and stop sharing. And it looks like we already have a pretty good crowd. I'm gonna pin your video here. So feel free to share. There, I think I'm sharing. Is that working for everybody? It is. Awesome. I can go ahead and begin. Yep. Okay, thank you. So hi everybody. So my name is Gabri. And today I'm gonna give a presentation on how to write a next derivation. So this talk is a refresh of an older talk I gave internally at my previous job. And they gave me permission to open source this talk. So I've updated it a tiny bit, but basically the context behind this talk is that at my previous job, I introduced Nix to the rest of the company. And one of the challenges I faced was how to teach Nix to people who had no exposure to Nix before. And I found that a very highly effective technique for doing this was to try to leverage people's existing intuition for other things to learn Nix. And so one of the things that I tried to leverage was their existing intuition for new makes, you know, like make files, you know, make builds, stuff like that. Because you can actually draw lots of parallels between Nix and make. And although they tend to get used for different things, like you can actually still learn a lot just by making analogies to how make works. So this talk is geared mostly towards people who don't know Nix and who do know make. But even if you don't know make, I think the talk will go slow enough that if you have questions, you can just go ahead and ask and I'll answer them. This is not gonna be a too long of a talk. I think like maybe 40 minutes long, I think it's roughly how much time I say this will take. So there's only like really two sections to this talk. And the first half of this talk, I'm gonna talk about the basics of Nix derivations. And this part of the talk, I'm gonna be making the most analogies to how between Nix and make. And the second half of the talk, I'm gonna be talking about how to write derivations which are less like make and more idiomatic to the Nix ecosystem. Because like what you'll find is actually that the way Nix is used idiomatically is actually very different from the way that make is used idiomatically even though it's still useful as a learning exercise to make the comparison between the two. So we're gonna start from like a very minimal Nix derivation. And so like when I say derivation, you should just think like something that Nix can build. It's like a recipe, a set of instructions for how to build something. Typically that thing that it builds is gonna be a package, but it doesn't have to be a package, right? It can just be a single file, just like make can build. Like the make targets are often like individual files. And this derivation is an example of that. We're just gonna be building an empty file using a Nix derivation. So this is a Nix comment that we have with a hash. And this is just saying that I'm gonna be saving this to a file called example zero dot Nix. And the way Nix builds work is that before the build even runs, Nix decides where your build product is going to go. It's gonna go somewhere in the Nix store. And so it's gonna hand you the desired output path via an environment variable. Typically out, it could be another environment variable, but in the common case, it's out. And so that's this environment variable right here. So basically your script has to make sure that by the end of the build, something has to be present at the path, which is pointed to by that environment variable. And so the simplest thing we can do is we can just create an empty file that path using touch. So to just walk through the script step by step, we say, first we're gonna import Nix packages, which is basically a large repository of not only packages, but also useful utilities for creating packages too. And one of those utilities is called run command. So you can just give it a bash script. And as long as that bash script creates something at the desired output destination, then it's a successful build. And so the way we would run that derivations, we would say Nix build that file. And so it's gonna say, okay, one thing is built. And so that's gonna create, so what happened is before the build, Nix looks at the derivation and it will hash it. And based on that hash, it will pick where it goes in the Nix store. And then, so the final destination that our script has to build is this, slash Nix, slash store, some hash, and then a dash, and then the name of the build. And so this example zero that you see right here, that came from this string right here. So we have to give our build some sort of a name. Nix expects that for every derivation. And so it picked that path for our build. It handed that path via the environment variable that our build runs. It creates that path using touch. And then after the build is done, as a convenience, Nix will create a sim link to the build. So it'll create, typically by default, that sim link will be called result. And so if we just cut the result, it'll just be an empty file. And if we run the build again, so Nix will repeat the process. So it'll say like, okay, I'm gonna look at the derivation. I'm gonna hash it. Oh, look, it's the exact same path as before. Let me check if there's something already there. And there is, so I don't need to build anything again. So it's a cache hit. So it doesn't replay the build if the build has already been created. Any questions so far before we go on to the next example? No, okay, then I'll continue. So now let's make an analogy to make. So the colon make file will be something like this. It says, so here is our build target. And then after the colon, if it has any dependencies, they would go there. But here this has no dependencies. So the part to the right of the colon is just empty. And then it says in order to build this build target named example zero, I have to touch that file. So right off the bat, this is a simpler, this make file is simpler than the equivalent Nix derivation. Like there's no Nix packages boilerplate or anything like that. But in the make file, there's more room for error. So as an example, like this is a sensible make file, but make also permits all sorts of silliness like this make file right here. So it says, oh, in order to build example zero, I need to touch example one. And that's not correct, right? That doesn't actually build example zero, but make except that. And if I try to make example zero, it's gonna keep succeeding with a false positive and never trigger a cache hit. Cause it's never actually building example zero. So Nix makes this entire class of mistakes completely impossible because Nix controls the output destination. And if you don't create it by the end of the build, then the build fails. So Nix will not accept it. So now let's make a slightly more interesting derivation. So we're gonna create a non-empty file whose contents are hello world. So we've changed the name of the file, including giving it a useful suffix. And now the file's contents will be some useful string. So if I run that build, it'll create, so first off, it will update the sim link. So it creates a new path in the Nix store. So a new hash, a new name. And so that path is different from the old path. It will not overwrite the previous build. It just creates a new build somewhere else underneath the Nix store. The only thing that it will actually mutate is the result sim link. So now the result sim link will point to the latest build, which is this hello.txt build. So if I cut this result sim link, you'll now print out hello world. So now let's make the comparison to the equivalent make expression. So it says in order build hello.txt, I need to echo hello world to hello.txt. And so the first time you run it, it'll run the command. And the second time you run it, it'll get a cache hit because the hello world, the hello.txt file has already been created. But now what happens if we change the make file to echo goodbye world to hello.txt? So if I run make again, it'll say that there's nothing to do because hello.txt, I already created it. But that's not correct. Like we actually changed the command. So like in principle, we should rerun the build if the build instructions change. So make is not that smart because make doesn't recognize that the build product depends on the build instructions. Whereas Nix is far in this way. So if I change the equivalent Nix build to change the instructions to output goodbye world to the destination output file, then that will trigger a new rebuild because Nix is gonna hash the derivation and the build instructions are an input to that hash. So that's gonna change the output path. And since the output path has not been built before, then it's gonna trigger an entirely new build. So Nix is much more accurate about detecting when things need to be rebuilt compared to make. And another way in which Nix improves upon make is that it preserves the old build. So in the previous build, the one with goodbye world that generated this path in the Nix store. Now suppose I edit my Nix expression. So now it writes hello world again. So basically I just revert it back to the old Nix code. If I rerun the build, then it's going to be a cache it because the old build product is still there in the Nix store. And so Nix is smart enough to reuse that instead of building it again. And that doesn't work with make because make generates all the build products. Well, typically make generates build products in tree within the repository that you're trying to build. So in order to generate a new build, it has to overwrite the old build products. But because Nix isolates each build and gives us its own directory in the Nix store, Nix doesn't have this issue. And Nix old build products are kept around until you run the next garbage collection. And so, so far we've been doing build products that have been individual files, but Nix is not limited to building individual files. You can build directories too. In fact, this is actually the far more common case in Nix. So, because basically Nix doesn't care what you put at that destination path, which is denoted by the environment variable out. So if you put a directory there, Nix is happy with that too. It'll still consider it a successful build. So here's a build where we will make the out directory and then store two files underneath there. And then that's a successful Nix build. And so we can build that and generates a new Nix store path. And now the result sim link is a sim link to a directory instead of a file. So I can LS it, I can cut files that are underneath it and that all still just works. So this is actually one of the really big differences between how make is used idiomatically and how Nix is used idiomatically. Make and practice and make the targets tend to be individual files. So like object files, executables, tar archives, I don't know, stuff like our header, I don't know, stuff like that. Whereas Nix, in Nix it's more common for both the top level derivation and all the intermediate derivations along the way to be directories instead of files. I mean, you don't have to do it that way, but that's sort of like the convention the Nix ecosystem has adopted. So what you will often find is that make is more commonly used for intra project build. So specifying how everything within a project depends on each other. Whereas Nix, well, more specifically Nix packages is more idiomatically used for inter project builds. So specifying how one project depends on an entirely different project. And very often Nix will actually delegate the intra project build logic to some other build tools such as make. In fact, you very often see Nix is used with make. So Nix is not often used for place make. It's often used to wrap a package which under the hood is using make. But for the purposes of this first half of the talk I'm still gonna be making analogies to make just to explain things. So like here's what an actual realistic package from Nix packages looks like. So if I build the lib icon package from Nix packages then what I'm gonna get is a directory tree which follows something like the file system hierarchy standard if you squint. So there'll be a bin directory containing the icon executable. There'll be an include directory containing header files, lib directory for library files, share directory for documentation and man pages and so forth. So this is like a proper package not just like a single executable. And so one of the cool features of Nix is that it's a real programming language. So what that means is that not only can you do things like bindings to define intermediate steps but Nix also supports string interpolation and multi-line strings too. So like for example, what I'm highlighting here this is a multi-line string Nix which is very handy for writing inline scripts. And the mnemonic here is that if you see like it's two single quotes at the beginning and the end of the string and you can think of those kind of like big double quotes that's the way that's the way to easy way to remember it. And within any type of string literal Nix you can interpolate any expression which can be cast to a string including of course strings themselves. Basically anything that sounds like supports a two string instance. But so here we're actually gonna using two features of Nix which are extremely useful for dependency detection. So I'm interpolating two things which are a little bit unusual and you won't really see it parallel to this in other build systems. So just like, you know, so this is the syntax for string interpolation. You'll see like a dollar sign, an open brace and a close brace and then an arbitrary Nix expression can go in there. And so actually let's just step back and let me actually explain what this derivation is doing. So this is the derivation that I'm using to build the slides that you're looking at right here. I mean, this is technically overkill. I don't need a Nix derivation to build my slides. You know, I could just run Pandoc directly for my terminal if I wanted to. But this is still a very illustrative example. And so basically what I'm doing is here is I'm calling Pandoc saying, okay, the input to Pandoc is gonna be the markdown slides and the output is gonna be the out environment variable. But we're doing two things to make this build work more accurately. So the first thing is that I interpolate the path to the slides that markdown file. And so what happens when I do that is that it's actually going to take the slides that markdown file, it's going to copy it into the Nix store and it's going to, so it's gonna freeze it and then it's gonna replace that interpolation with the fully qualified Nix store path. And so because it does that, anytime that slides that markdown changes, it will freeze a new copy, which will generate a new Nix store path, which will change the derivation. So the derivation will automatically detect when slides that markdown has changed and it needs to be rebuilt. So I don't need to tell Nix that slides that markdown is a dependency of this derivation. Nix can actually just automatically infer that. And here's something a little bit related to that. So here I'm interpolating the PanDoc package. So you can imagine that if we were to build this package, you would get something kind of similar to what we got with lib icon. So we have some directory tree that has been some directory underneath there containing PanDoc. And so if I interpolate a Nix derivation inside of a string little, what will happen is that it will build that package, that derivation. And then that will generate a product in the Nix store. And then it will replace the interpolation with a fully qualified path to, in this case, PanDoc. And so what we'll actually be here is like slash Nix slash store slash some long hash slash bin slash PanDoc. And this is important because suppose I upgrade Nix packages or change PanDoc in any way, like maybe I patch PanDoc. If it happens and the PanDoc will get rebuilt, it'll get a new Nix store path, which means that there'll be a new hash here. And then that means the whole build changes and needs to be rebuilt. So Nix is smart enough that anytime PanDoc changes, then the build will get rebuilt too. So this is another great way to enforce intelligent dependency detection. Actually, let me just quickly switch to my terminal windows so I can show what this actually looks like under the hood one second. So here's my terminal window. Let me actually just make it a little bit easier to read just a second. Let me just, is that clear to people? Is that a large enough resolution? Yeah, we can see it on here. Okay, good. So here's an example of what, so in Nix you can, so Nix, I'm not gonna go too much detail here, but Nix, whenever you take a Nix expression and build it, there's an intermediate step where it translates that Nix expression to a .drv file, which is a .drv file sort for derivation. So this is actually what a derivation is. It's sort of like a language agnostic set of build instructions. And we can actually see what Nix does to the build recipe. So Nix took that script that I gave it and says, okay, so here's actually gonna be the fully qualified path to Pandoc right here. So and actually, it doesn't even need to build Pandoc to do this. Cause remember, for every Nix build, it knows ahead of time before the build even runs what the destination path should be. So even before we built Pandoc, it knows that the path has to be slash Nix slash door slash NC5N5 something, something, something. And then same thing for the slides that mark down file. Here, this is the Nix store path to the frozen copy of that same file. So that's actually what our Nix code is translating to under the hood when we run the Nix build. So now I'm gonna switch back to my slides very quickly. And if you wanna learn more about derivations, there's a talk on YouTube I've given called Nix under the hood. If you just search for that, you'll find a talk I've given going into a deep dive into how derivations work. But anyway, going back to the slides. Okay, so, so if I build the slides, then it's looking to build basically the same slides I'm showing you right now. Actually, I'll just go ahead and, I'm gonna build them in the other terminal window. You can't see this, but I'm gonna open them. And now you can see that these are the same slides. But if you look very closely at the top of the browser, window, you'll see that now this is a path in the Nix store instead of my local directory tree. So this is built using Nix. Okay, so now let's compare to make. So this is the analogous make derivation. And so make I mentioned before that the format is here's the target that we're trying to build. And to the right of the colon are all the targets dependencies. So like slide.markdown here. But carefully note, first off, we had to explicitly declare that slides are marked on as the dependency of the HTML file. So make unlike Nix cannot automatically detect that. You have to explicitly declare it. And if we forget to do so, well, then it's an inaccurate build. So make is more error prone in that regard. And also make, there isn't really a good way to specify that there's a dependency on Pandoc, right? I can't just put like, you know, Pandoc to the right of the colon, that's not gonna work. I could try to like put a fully qualified path to, you know, the Pandoc executable. But that's not really gonna work well because then the make files not gonna be really portable between systems. So typically what you do in make land is you just ignore this issue. There's not a really good solution to this. And also like before, again, there's also no dependency on the instructions themselves. So, but we already covered that. But Nix is not perfect when it comes to rebuild detection. So, I mean, obviously we try as much as possible so that Nix can accurately detect when something needs to be rebuilt. But here's an example of a simple derivation that we're Nix can't know that it's impure. So this derivation just takes the Unix date command which just outputs the current date and then saves that as a result. And this derivation is obviously not deterministic, right? It depends on when I run it, what result I get. But Nix doesn't know that, right? As far as Nix is concerned, if I build it and I try to build it again, well, the recipe hasn't changed since the last time. So Nix is like, oh, well, nothing needs to be rebuilt. So Nix cannot automatically to tell that our derivation is not deterministic. Because the way Nix works is that if the derivation has not changed, then the result has not changed either. So to roughly summarize how the various tools work, the way Nix works is in terms of timestamps. So to go back to here very quickly, Nix looks at the target and looks at dependencies. And if the target's timestamp is older than the dependencies, then it'll trigger a new build. If it's newer, then it doesn't need to be rebuilt. So that's how Nix works. The way Nix works is that it takes the instructions, specifically it takes that .drv file I showed you earlier. It hashes it. I mean, actually, sorry, maybe I misspoke, but basically it takes the instructions and it hashes them and then that's how it detects whether or not there needs to be a new build. For completeness, Nix actually has another way of building which is content addressable derivations. I'm not really gonna cover those in this talk, but I'm just mentioning them, they exist for completeness. Okay, I'm gonna stop here and just see if people have any questions before I move on to the second half of the talk. There's been some questions popping up in the chat that you might scroll through just to make sure everything's kosher there. Oh, I didn't see that yet, let me see. So the first question is, is the hash based on the contents of the output in addition to built instructions, e.g. writing the current time stamp? By default, no. The hash is only a hash of the input derivation, the instructions. So Nix doesn't care what the output is by default. Okay, so since you asked, I'll go a little bit more into content addressable derivations. So if you want the hash to depend on the result, you have to basically tell the Nix what the hash result will be. So you'd have to out of band a priori know the hash, or try to just run it and see what the hash would be. Gabriella, I think it would benefit everyone if you talked about the isolated build space, how network can't be accessed and everything should be applied ahead of time. Oh, yes. There's some confusion about how stuff can be known if you don't know stuff. Network access, file system, CHU, stuff like that. So let me first talk about network access. So by default, at least on Linux, Nix builds are sandboxed, which means that, well, one of the consequences is that a sandbox build, by default, cannot make network calls. And Nix does this to help make the derivations more deterministic, right? Because network calls can be a source of impurity, like maybe the resources aren't available at the time that the build is run, right? And so, but there is one exception where you can make network calls is that if you know in advance what the hash of the build is going to be, in other words, if it's a content addressable derivation, then that's one exception where the Nix sandbox will allow you to fetch something from the network because Nix, because the content addressable derivation fixes what the result should be. Like there's only one thing that will produce that hash, modulo, you know, very unlikely hash collisions. So in fact, we're going to see an example of that in an upcoming slide where we're going to fetch something from the network and we have to specify what the hash should be so that call succeeds. And so yeah, so content addressable derivation is one in which you know in advance what the derivation is going to be. And because of that, then Nix will actually base the Nix for path off of that known content addressable hash. Was there something else you wanted me to elaborate on there? No, no, I think that's good. Just to let people know that like the build file system is scoped, you can't access things in your home directory or in temp or anything else. You have this like isolated space and also like the network has to be kind of evaluated ahead of time through like a fixed output derivation or something with content address derivation. Yeah, and the idea is that if you pin the output using the content addressable hash, then you're allowed to do evil stuff because it doesn't matter what evil stuff you did to get to the results because the result is still fixed. So that's the reason why Nix allows that. Thank you. So somebody clarifying chat, the hash only depends on the inputs and dates in the Nix build environment should evaluate to the Unix start time. That might know, well, actually I just tested this. And so at least for the example I gave, I ran it yesterday and it's still, at least on a recent Nix packages and recent Nix, it still doesn't evaluate to the Unix start time. But it could be that it might be because it's not using the standard environment. And I haven't yet talked about the standard environment, that's the next section. And because I'm just using the simple run command builder which doesn't try to pin the source timestamps. In fact, actually when we get to there, I'll try to show the part in the standard environment that pins that timestamp. So the question is, what about fetch URL, URI to some date service? You wouldn't be allowed to fetch something unless it was a content addressable derivation. So that would pin the results. And if the result changed, then it would just be a failed build. Because Nix will check that the result matches the content addressable hash. And there's some follow-up clarifications. So for slides that mark down, the hash is the hash of the slides that mark down file. Not the hash of the instructions for building slides. Yes, that is correct. It's because there are no instructions for building slides that mark down. So actually if I just switch back to my terminal very quickly, I'll just do a little bit of a deep dive into shallow dive into derivations. So if we look at this derivation format, there are two types of inputs. There are two types of dependencies for Nix derivation. There are input DRVs, which is for input derivations and there are input sources. So input DRVs are other derivations. So other.drv files, these are things that still need to be built. And input sources are things that do not need to be built. Just like flat files, which are just inputs that bootstrap things. So slides are marked down as one of those flat inputs that cannot be built. It's just like it's a plain textual input to our Nix build. So that's the distinction between the two. All right, let me see. Is there any other questions? Yes, so JSON-to-DAL is something I often use for pretty printing the Nix derivation format because the Nix derivation format normally displays JSON which doesn't support multi-line strings, but DAL does. So if you format it through JSON-to-DAL, if you format it through JSON-to-DAL, it'll give you nice formatted multi-line strings for your build instructions, which is very handy for debugging. So next question is, how does Nix calculate out? It would need the full path of the current derivation to calculate the hash. But if it does use that later, doesn't that change the current derivation? It's because the path to the current derivation, so when I said that it hashes the.dirv file, I misspoke. So that is not actually an input to the path. So Nix hashes several fields of the derivation. So derivations are basically just records in Nix. So to be pedantic, the minimum thing you need to have, well, the minimum thing that you need to trick Nix into thinking that something is a derivation is you just have a record with one field named type whose value is derivation, the string derivation. And if you do that, Nix is like, okay, this is, I guess the derivation. You actually need some other fields in there to make it work, but that's kind of like the bare bones minimum. Nix will then, after it completes the hash, it will then add those additional fields like the expected outputs and stuff. So those are not inputs to that hash, and therefore you don't get that catch 22 issue. So is slides that mark down a content addressable derivation? The answer is technically no, it's not a derivation. So technically, I guess there are three types of things in Nix. There's derivations which are hashes of their inputs, there's content addressable derivations, and then there's just input sources like file-based inputs to Nix. So it's not a derivation at all, and it's not a content addressable derivation. So what are types in Nix? So what is the type of pandoc? So Nix doesn't exactly have a type system, but you can imagine that like Nix has strings, integers, lists, and most importantly records, or actually Nix calls them attribute sets. That's Nix terminology for it. So all derivations are attribute sets that happen to just like have a special format to them, but they're just glorified records. Like essentially Nix packages is just like records all the way down. It's just like a giant tree of records. Okay, so there, I think we've caught up with questions. Let me just do that. Got a question, Steve. What? Oh, I've got a few. Yoltham, hi, can I have two questions? Yeah. Go ahead and do that one. Go ahead and do that one. Oh, sorry. Go ahead. Can you clean up the like all of our hashes? Oh, do you want me to switch to my terminal window really quickly? Well, which hashes were you interested in seeing? The directory hashes. The output hash. Yeah, the output file. I'll make sure you heard your question and say it louder. Let me switch to my terminal very quickly then and then you can, let's see, because it has the most. So like, you mean like these hashes here or? Yeah. Yeah, those hashes. Yeah. So these hashes are, so these are not inputs to the, so these are not inputs into the build. So like actually what goes into the hash function is not this. So that first it takes some inputs, it hashes things that it will add after the fact, the expected output path like this right here. So the output path is primary cache? Yeah. So this path is going to be cached once it is built. And another question? Yes. Hello, can you hear me? Yes. Hi. Hi. Well, before that, this is not, this is not, this is not, this is not, we just create a big file that all it does is create a date and if you wanted to get exactly the weaver, does that make, does make do the same thing or it may also have it received with non-deterministic system? Oh, so make would have that same issue with non-determinism. So like that same date example would also cause and make the same problem. So it's not, that source of non-determinism is not a problem unique to NICS. Okay. Yeah. And so is there like anyone trying to fix that one or is it not a common problem to all of you? I mean, the closest thing NICS has to a fix for that is like to make a derivation content addressable in which case then like NICS would detect that it was impure or something had changed and then prevent the bill. But, oh, sorry, there's actually, sorry, actually NICS does have solutions along this line. So there is a NICS option to automatically do a test rebuild. And if the rebuild produces a different result from the first build, then the bill will fail. I forget what it's called, but I can look it up really quickly. Let me just switch to my browser. So like there's somewhere in the NICS.com, you can say, I don't know, it's like, there is some option I cannot remember what it was, but like you can say like how many times to repeatedly build it just to make sure the derivation is deterministic, but I cannot find it. I thought it was like rebuild or, I know, I believe there's also a command line option too. So like there's a dash dash rebuild option to many NICS commands that will also like, you can use the test that a derivation is deterministic. Let me see, one last check. No, I can't find it, but I'm pretty sure there is such an option somewhere in NICS. Okay, so now let's get on to the standard environment. So now this is the part where we're going to depart significantly from how NICS works, and these are going to be more idiomatic NICS derivations. So like before, we're going to import NICS packages, but this time we're going to be using a different utility from NICS packages. So we're going to be using this make derivation function. And the running example we're going to be using here is building the hello package. So there's like a new hello package, which illustrates, you know, new best practices for how to build an auto tools style package. And we're going to use it here for illustrated purposes. And so this make derivation function is very smart. So we don't actually have to give it a lot of information in order to build this new hello package. The only thing we need to tell it is, what's the name of the package? Hello in this case. And we could often also put the version in there too, but we'll just skip that for right now. And then we also are going to put in the source, how to fetch the source for the package. And so this is actually a nested derivation. So this is an inner derivation just to fetch the source archive. And that's an input to this outer derivation here to actually build the hello package. So there's going to be two separate derivations involved here. And this right here is actually an example of a content addressable derivation because it needs to fetch something in this case, like from some mirror. And so in order to make that never call safe and reproducible, we have to add an integrity check for the expected output hash. So that's necessary to make this work. And then, and yeah, that's it. So we just give it this source archive and then standard, and then, sorry. And then make the derivations like, I know what to do, I can build this now. And then that's enough. So now we're going to run a nix build for the hello.nix file. And this time there's going to be two builds instead of one. So the first build is going to be fetching the source archive. And the second build is going to be like, we're actually building the hello package. And if we log the result, we'll see the build steps for the various things. I'll go into more detail about these later. But the final results is going to be like the package containing an executable and also some documentation like man pages. So basically this standard environment has a default build script if you don't specify one. And conceptually what it does is it first unpacks the source archive, then it'll CD to that directory. And then many packages that use the auto tool system will have like a configure script you have to run. And typically nix will configure it so that the prefix for the path needs to be installed will be the out directory. And then nix like runs the various make commands like make to build the package and then make check to run tests. Then make install will then install the package at the specified prefix, which is just out. So I'm over some playing a bit, but that's basically how it works in the common case. And there's a long, if you wanna see like the gory details of how it works, there's this setup script, which you can find here. And I wanna actually see if we can find a thing about like the timestamp or the epoch. Epoch, all right, set. I could have sworn there was like something, well, it might be a different, like a shit. So they're also, in addition to this, they're also hooks too, which do stuff, but I can't find that logic here. But anyway, the key thing is it's long, it's complicated because it does a lot of stuff and it's also highly customizable. It has tons of hooks in it. So the way the standard build environment works is in terms of phases. So you have the unpack phase, which takes the tar archive or whatever and unpacks it. And then we apply patches, if there are any, we run the configure script, then we build the package, then we run tests, then we install it at the output directory, and then there's some like Nick specific fix ups. And if the package supports a make install check step, it'll do that. Similarly, if it supports and make this a step, it'll do that too. And it's highly customizable. So like for each step, you can add like new flags or arguments to that step. For each phase, you can add like commands run before after that phase, which is very convenient. You can add patches to the source, you can add or remove entire phases if you want, or you can just selectively enable the phases that you're interested in. And in the worst case scenario, you can just throw it away and just like write a dumb batch script, just like we did at the beginning of this talk, right? You don't have to use all that complexity if you don't want it. It also has lots of really useful utilities in scope too. So for example, like it has some utilities that can go through the source archive. And if it sees any hard coded paths like bin slash SH or bin slash Python or whatever, it can replace those with the equivalent, fully qualifying Nix or packages. So it has like lots of very useful utilities to make it as easy as possible to package up things that you find on GitHub that are not Nix aware. Another nice thing about the whole phase system is it makes it much easier to debug builds too. So let's say your build fails for whatever reason, you need to say Nix shell and you give it the duration that you want to replay. And in the simple case, you can just say generic build and they'll replay the build up until it fails. Or you can just run the phases step by step. So you can just say, okay, first run the unpack phase, pause there, then run the patch phase, pause there and so forth. You can just do this after every phase to see what's happening, which is very handy for like debugging builds. Okay, so the final example for this talk is I'm just gonna like show an example of packaging up an existing non-Nix aware package using Nix or Nix packages specifically. So here I'm gonna try and package Redis, which is available on GitHub. And so like before, we're gonna use Mac derivation. So you just take, we take advantage of its automation. The main difference is that the source input is gonna use, it's not gonna use a mirror, but we're gonna use a utility called fetch from GitHub. So for this utility, we just give it an owner. So like anti-res in this example and a repository name, so Redis and also revision. And actually we should put the hash here too. I just left it out for simplicity here. I'll show how to take care of that in just a second. But you can't actually put null here and in some cases that actually works, but it's not a good practice. And so if we try to build this, it's gonna fail. And so let's look at the error message we get. It says, so during the install phase, it's gonna fail with cannot create regular file slash user slash local slash bin slash Redis server. So this is bad. Redis is trying to install something in a place where it should not have permission because if you don't want it to install under slash user slash local slash bin, we want it to install in next door, right? We don't want Redis messing with our global package set. At least not as a next package. So we'll get a permission night error here. Oops, so if we go to the Redis GitHub repository. So it looks like basically what's happening here is Redis is not respecting the prefix for the package. So, but if we go to the Redis repository and we just search for like prefix, it'll say, oh, yeah, actually it feels Redis does something a little bit weird and non-standard. That's why it didn't work the first time. It says what you're supposed to do here is say, make prefix equals your desired up. Sorry, I don't know if that's easy to read, but basically you just say make prefix equals the desired output path and during the install phase and that'll be enough. And so what we want is for this prefix to be the out environment variable. So the one change we need to make to our derivation is we're gonna use one of the many customizable hooks of make derivation, which is make flags. So if we go back to our set of scripts somewhere in here, there is logic for respecting this make flags setting or option. And so we say, okay, make flags prefix equals the out environment variable. And if we just make that one adjustment, now the bill works. And the results just gonna be like, you know, directory tree containing the build executables and nothing more. So in the previous slide, we had to like skip over this hash. And we'd like to make it easier to manage stuff like, okay, what revision to build? What should the hash be? So we don't have to like guess and check. And there's some ways you can do that in Nix. So one way you can do this is using a handy utility called. So I mean, so this slide was written back before we had like higher level tools like I don't know, Niv and such that would do this kind of stuff for you. But like conceptually what these tools do under the hood is very similar to what I'm showing you right here. Which is that there's a useful utility called Nix Prefetch Git where if you give it a URL for a Git repository then you get something like this. Sorry, like this URL here. And it's output is JSON. But we can still actually take that JSON and incorporate it into the Nix bill. So here's an example of what the JSON looks like. And here the key fields of interest are gonna be the revision and the SHA 256 hash. And we can incorporate that JSON file that we just generated in our build. So we can have Nix, so within Nix we can read files like a JSON file as text. And then also within Nix there's a very useful utility called from JSON which will parse the text string and convert it into the equivalent Nix data structure. So for example, a JSON record will get converted to a Nix attribute set. So now we can access the field to the JSON object as Nix attributes. So now I can say, okay, the revision for this derivation should be whatever was the revision field of the JSON object. And same thing for the SHA 256 field too. And then that still works just the same. Okay, so yeah, so basically you can in principle use Nix as a better make. In practice, Nix is more commonly used for building package at the granularity of packages instead of at the granularity of individual files. And it's actually much more common for Nix to wrap a package which is built using make. But even so, Nix is actually pretty decent as a make replacement because it fixes lots of the design flaws in make. So it has like more accurate rebuild detection and better suitability. And also feels like it's a real programming language like make, like anyone who's ever had to use make knows like how much of a pain it is to do very simple things in make. That things that are much easier to do in Nix. So yeah, I think like that concludes this talk. And I think I'll just take questions from the audience. Oh, I should probably start with a chat actually, sorry. Okay, go start with the chat. Yeah. So how are these slides regenerated both with Nix and I think the ones I'm putting from right now are generated just from the command line, not with Nix. That's why you don't see this like slash Nix store prefix to the in the address bar. But like the formatting of the code blocks and everything, like what did you use as a preprocessor? Like what generated your HTML? You just hand coded it and had like a CSS template. Oh, no, no, no, no. So this is a feature of Pandoc actually. Let me go back to Pandoc command. Okay. Yes, Pandoc is super. Well, I mean, definitely it's not a feature of Pandoc. It's a feature of Slidy, Slidy.js. So when you convert Pandoc Markdown Slides to HTML you can specify what backend to use for doing that. And so Pandoc has a Slidy backend for this purpose. So you just say dash T Slidy and that's and also dash S for standalone helps. And sorry, if you said you built this presentation in the beginning, I missed it. Sorry about that. Thanks. Oh yeah, no worries. Another nice backend. Actually a backend I think looks a little bit nicer is reveal.js. I use that more from many of my newer presentations because it looks a bit nicer but it would take a lot of reformatting of this presentation because things are much more, you have a lot of space to work with when you use reveal.js. Thank you. So the next question is how can you know where to look for source code for various next builders? Oh, good question. So I just like look through. So, okay, so, so, so, so. So the best place to begin is so there are three manuals you should always know about. I'll actually take only four but three of interest. So there's the NICS manual. There's the NICS packages manual and there's the NICS OS manual. So one of the very first things I teach beginners is which manual to look in for what they need to know. So for this question, the correct manual is NICS packages manual. So this NICS packages manual is probably the most useful and interesting manual of the three. And especially like, this is where most of the annoying bits in NICS come from. But yeah, so this explains stuff like the standard environment. So there's an entire section of this manual dedicated to explaining the standard environment. And also, but also there's a very useful subset of NICS packages too, which I should point out, which is the trivial builders. So trivial builders. I actually use those quite frequently. Yes. I have it bookmarked somewhere. Yes. So like run command, the one that I was using at the beginning of this talk, that's from this file. So run command is one of these trivial builders. Another trivial builder would be write text. So basically it's like write text or write text file. Basically you just give it a text string and it'll just like turn that into a file in the NICS store. See what some of the write script. Actually, one of my favorite ones is write shell application. It's here, right here. So this one's nice because first off, so you give it a shell program you wanna run. And it takes care of like giving you the whole boiler plate. So like the shebang and all like the usual, like set dash east dash u dash type fail. But also I don't think it does, it will run shell check on your script too. So if shell check fails, then the build will fail. So it's very handy for just like production grade bash code. Wait, what does shell check? Sorry, what was the question? What is shell check? Oh, so shell check is something that, it's like a static analyzer for bash code that finds lots of very common shell scripting errors. I highly recommend using it. Either indirectly via write shell application or just like just try it. It's a really great program if you do any sort of production grade bash stuff. I guess I have one more question about sort of trivial builders then is, I was really struggling with, I'm on like an older version of NixOS and they don't have like build node package. So there's all these like disgusting ways of getting like Nix packages to be pinned for Nix. So, but, and now they just have a builder for it, but is there a way to just like, you know, circumvent the sandbox for like, you know, if I just want to do like an NPM install or something like that. Or like a build. So, if it is content addressable, that's one way. There's, you can also just turn off the sandbox, worst key scenario, that is an option if you really have to. Right, but is there a way to do that at like a, like a specific derivation like granularity because you can, I think you can pass like an environment variable for like, for like your Nix builds, but I was just wondering if you had a similar experience with trying to get around it. So I think there are some very super secret Nix options you can set to like allow some impure fetches, but I don't remember them off the top of my head. It's like Nix impure HTTP. Here we go. So Nix has some special options you can set that may permit this sort of thing. So if you just search for like Nix impure envars or impure HTTP, this may get, I have to check. It's been a long time since I've used this feature. So I could be very wrong here or off base, but I think that's how you would bypass those sorts of limitations. Okay. But yeah, I think there are ways to do this, but it's not fresh on my mind. So use impure envars, is that what it is? I guess. Sure, I'll take a look into that. That's interesting. Like as an example, like HTTP proxies, right? Yeah. Also, sorry, there's nothing you can do which is that you don't have to turn off the sandbox completely. You can also whitelist specific paths in a sandbox too. Not on a, well, actually you might be able to do this on a per-derivation basis too, but again, so like Nix, sandbox, impure, I don't know, exception, I'm just bawling here. Yeah, I believe there should be a way to do this, but I just don't know off the top of my head. And I guess like to that end is like whenever you're building a derivation, like how the heck do you even know what the shape of the arguments that you're supposed to supply? For example, there are types in Nix, right? And sometimes whenever you build, it'll scream at you like, oh, what is this? But is there any way to sort of like statically check that? Because I know it's a lazily evaluated language, but it's like, how do you actually know what the shape of a MK derivation is? Like it's just a convention of... So I'm gonna shill one of my own blog posts about exactly this issue here. This is called the hard part of type checking Nix, where I explain that I believe it is possible to write, I guess a static analyzer or type checker for Nix, but it's actually a very non-trivial problem. Like it's not just simple like, oh, just throw a Henry Milner type in friends, you know, type checker at Nix. It's actually much more complicated than that. And this blog post goes into many of the challenges behind getting that working. Like this is actually one of my big pep projects is trying to write a type checker for Nix. But the short answer is it's a very hard thing to do. Is part of the reason because it just takes like dang long to build everything? And if you're in a dying way? No, it's basically because nobody actually uses Nix, the language in any at scale, right? So Nix packages and Nix OS have basically created these embedded domain-specific languages in Nix. And those are what people actually use. And that's actually the thing that actually makes more sense to type checker to natively understand. But if you just try to throw a naive type checker for just Nix the language at, you know, Nix packages or Nix OS, you're just gonna get very confusing results that are still not gonna be very helpful to developers. Like at best you can just type check Nix in the small but not in the large. Okay. Also for Nix function search, since that was part of the question, there's also utilities like Nix Doc you can use for searching say Nix packages for useful utilities and such. And you can also, okay, so you can also, yeah, grep, grep being Nix packages is what I do. That's how I, I don't actually use Nix Doc. I just like search Nix packages by, you know, like a peasant. Okay, and, oh, there's somebody mentioned Nill. Okay, and shell checker. Okay, so that looks like I've got caught up on chat questions. Do people have any additional questions? Yeah, so you marketed Nix as, or I should say the title of this talk was something like Nix as a replacement for make. But in my head, it's like a different layer. And are you advocating for the deprecation of make or are you like advocating for a Docker file like solution where it exists in the repo at some level? And if you have the tooling to support it, you can use this better system, better, right? Some metric. Yeah, so like, I would like to see Nix actually replace make for many of the technical like advantages I mentioned. And Bazel and Docker and everything too. Exactly, yes, yes, but for the technical, but so the issue here is that, sorry, what was I gonna say? So, definitely at the time this talk was written, like that was not a realistic option because, well, anyways, like that was more for like educational, like, okay, here's a Rosetta stone, like here's make, here's Nix side by side. Sorry, well, it's not an option to replace make in industry or what? Just, well, so back then there were severe technical limitations, the most important of which is that, back then there was no such thing as recursive Nix. So recursive Nix- I'm sorry, you say back then, are you talking about this talk? Are they talking about preparing for this talk? Sorry, I forgot to mention that, I think I mentioned at the beginning that this talk is a refresh of a talk I gave years ago at my old job. So back years ago, that was not even really an option because there's no such thing as recursive Nix. So recursive Nix is basically the ability to run a Nix build inside of a Nix build. So like, that's all you would need if you were like, if a Nix build was trying to build a project which internally used Nix to build itself, then you would need recursive Nix. So recursive Nix, I believe does technically exist and new versions of Nix. I don't know if that actually makes this possible or not and there's several other issues that may still come into play. So like, it might actually be feasible these days but I haven't really kicked the tires on it yet. One other thing that kind of concerns me is, I think make has a notion of targets that are stale or fresh and it can kind of spread out the workload and not build a library again if it's already up to date. But Nix will kind of see the whole derivation as atomic and rebuild everything. Is that true? Like in a C application when I have a bunch of shared libraries, do I pay a penalty for using Nix? So there are two ways to interpret this question and I'll answer both of them. So what is that? I appreciate it. Is if we build Nix at the granularity of an entire package, obviously then if any one thing in the package changes, we have to do a whole new build, right? So if you implemented Nix naively on top of a make build system, you might see severe degradations and iterated builds, right? Yes, although so even for that, I know there's an open PR against Nix packages. I don't know if it's emerged yet but basically to add like a layer of incremental build support. For the idea is that if you have like some base build which has already built all the build products, you can use that as an input to downstream incremental build. So basically it'll just like start newer builds using the existing build products from that older build. So if my crates are built already and 90% of them are up to date, cargo won't have to rebuild all the time making it just do 10%. And is that kind of language agnostic, this idea? Implementation? Yes, it is kind of a language agnostic. Awesome, awesome, awesome. So the second way to answer this question is so Nix also, so here's something that comes up often which is that you would like to have, so one thing that make would do which Nix does not do by default is that if some target hasn't changed, well, actually I don't know if make does this but I'll just mention it anyway because it's very cool. So let's say that some dependency of, I don't know, Perl changes in a trivial way. So like maybe I added a comment to GCC, so I have to rebuild GCC but that comment doesn't really change GCC's behavior, right? So the Perl results, like the actual built Perl executable doesn't change. It'll be pretty lame to have to then like rebuild everything that's downstream of Perl just feels like I added a comment to GCC. What does not change mean? Does not change mean that the hash of Perl would be the same or does not change the semantics? It means that Perl would produce the same, the same output, the binary hash of the binary. Okay, got it, thanks. And so the thing about Perl is that, so Nix actually, so Nix has a thing that's called the content addressable store. Again, very bleeding edge, which in theory Nix can be smart enough to see that if the Perl build didn't change, so even though Perl's dependency is technically changed, if its result didn't change then it won't have to redo downstream builds. So it's just gonna prevent a whole bunch of gratuitous rebuilds from happening in that case. Again, very bleeding edge. I've never kicked the tires on this, but in theory it's something that should exist. Is that not the way Nix works now? Like if I have a dependency tree and the middle of that dependency tree is up to date, it will still build everything after? Is that true? Yeah, spite of all that will still rebuild everything downstream even if it's like, yes. I didn't know that. I thought if it hits a point where it's seen that node before, it will kill the subtree and not execute it. Yes, so this is actually outlined in Yilko-Dolstra's thesis, the content addressable store. And if you just search for Nix content addressable store, you'll see several examples, you'll see lots of resources related to this feature. Okay, thank you. Is that because the store path changes whenever you add a comment? Oh, sorry, what are you saying? Is that because the store path changes whenever you add a comment to it? Yes, because like anything that's an input to Nix, including source code, can perturbed the hash. So I had a question, I'm new to Nix. I've never actually used it, but it looks really cool. I guess just trying to wrap my head around how one might use it besides like for a make file. I mean, are people using this for, I can see like a use case for integration tests, right? Where I have like a bunch of binaries. I wanna make sure that they all work well together. I can pull them down, they each have a hash and it won't run the tests if the hashes are the same from the last time and it will run the test if the hashes are different. I mean, is there a use case like that that's sort of outside of the pure build situation? So Nix and Nix tests can be builds. So in fact, that's actually how Nix OS tests work. So a Nix OS test is basically as a Nix build that produces a result. So you can actually codify tests as Nix builds and then you get all these nice properties like if the inputs to the test don't change and the test doesn't need to be rerun. Yeah. So yeah, you can do that. In practice, it tends, again, it tends to not be done at the granularity of individual tests or individual files but it could in principle, it'd be done this way. I guess I was thinking like in terms of binaries, right? Like if I have two build artifacts, I wanna make sure that they run together, hash them and use them as inputs. But it's really neat. I like it. Thanks for the talk. Chris, were you asking about like what the industry relevance of Nix is as a tool or why people might adopt it? Partially that, but partially if other people are using it that way, that seems to me like a way that I could potentially use it in my build chain, I guess is the comment. Okay. I just wanna inject some thoughts if I can. And my main value for Nix is that someone can write an arbitrarily complicated expression that they know builds on their architecture. And I can just pull, not have to install any of the build dependencies. And I can run the same command to build that software, whether it's a Rust application or a Go application or a Python application or a C application. I just run Nix build. And as long as the derivation built on their architecture, it will work on mine because the builds are reproducible. So it gives teams a guarantee that their code will build if it ever built before or if it built for your friend, it will build for you. And also it comes with a large degree of like bill of material security because you have hashes on all the inputs and everything's tracked through like, well through the flake lock if you're using flakes, but like everything's hashed and addressed. So you have guarantees about the progeny of all your inputs. So those are the huge value adds for me. I don't know if that was something you were asking about but I just thought I'd put that in there. No, thanks. Yeah, it's helpful. I wanna add one more thing there, which is that the talk I mentioned earlier, Nix under the hood, it also explains how like Nix, one thing I think a lot of people don't appreciate about Nix is that you can actually change out the front end language. So Nix actually has like three, conceptually three stages. There's the Nix language which is compiled to the derivation format which is language agnostic. And then that is translated into build products. So if you don't like Nix the language, you can in principle replace it with like some domain specific language that your company likes to use. Like if you don't, if you, if whatever your engineers just don't like Nix syntax or whatever. In fact, that's actually what GUIX does. So GUIX is basically a Nix but with a Gael scheme front end instead of the Nix language being the front end. Is it recyclable? I think I'd be able to. Oh, go ahead. Oh, I was just saying that you might be able to achieve that integration testing with a tool called Morph maybe. So you can run basically health checks on various hosts and in those health checks, you could probably just program whatever like cross network communication you need to happen between them. And then if like. No, if I may interrupt, there already is a mechanism for doing this in Nix. So that's the Nix test mechanism already supports exactly that. So you can test clusters of machines, you can like start and shut them down, make network calls between them. You can even like force crashes, take screenshots of them, like all sorts of things. Dang, I didn't even know those. Yes, so I'm gonna show another blog post. How to use NixOS for lightweight integration tests which goes into detail how to do this. That sounds like way better than what the heck I was using. Cool, we'll talk about that. Check that out. Gabriel, I wanted to ask, you were talking about, I don't know how to pronounce it, GUICS. I say GUICS, but GUICS or GUICS? Oh, GUICS or GUICS? I don't know how to pronounce it. I would say GUICS, that's what people are saying. Okay, GUICS. Yeah, this is cool. I understood that it was a completely separate software, like, I don't know how to say this, like project, then Nix, and it doesn't recycle the Nix store, doesn't recycle the builder, doesn't recycle any of the packages. Is that true? And it just replaces the Nix with S-expressions or is it really recycling a lot of the engineering? I could be wrong, but I thought they at least forked the Nix store implementation. Okay, I'm not sure. I'm not, I don't know. So what I do know is they are not reusing Nix packages. So like, you know, the large suite of Nix expressions written in Nix. They're definitely not, they're like doing this. The coverage of GUICS is much smaller, right? That's what I know. Yeah, I think there's like, I think there are some differences in like, what, how packages are idiomatic. So like, so Nix packages is not just a set of packages, it's like a set of idioms for building things and how to override or tweak things and so forth. And so GUICS has its own set of idioms that are, I've heard different from Nix packages. I never use it myself, but I believe like the underlying, like the whole Nix store machinery and mechanism, I think that was just plain forked from Nix. What problems did GUICS solve that Nix doesn't? S expressions? I only know what I've heard, but like, I think one of the things that they're trying to do is actually start from a more primitive base layer. So like, I think Nix, like the, the foundations of the Nix ecosystem are like, I don't know, some binary download of GCC and like a few other things. And I think GUICS actually tries to have like a more, a smaller, I guess, foundation. More primitive? Yes, exactly, a more primitive foundation. Okay, okay. So it starts with this interpreter and then it builds another whisper interpreter and then it builds another whisper interpreter. Something like that, yeah, isn't it? I think also just because like, they have their own, like, again, they have their own idioms for how to like overlay and tweak things, which differ from Nix packages too. So I think like also just provide, like I think Giles scheme the language is not much of a value add, but I've heard a lot of people who do use geeks or GUICS, they praise those idioms that I was talking about. They say like they're much easier to use than Nix packages idioms. Thank you. The better programming aspect of Giles scheme, maybe they're thinking adds a little something to Nix. I'm not sure how it is as far as like how energetic macros or the scheme system is, but maybe that might be a reason they were thinking it might be a value add, respectively. Yeah, I mean, in my opinion, the thing Nix really needs is a type checker or something. Like that is the big omission. And yeah. Also, I think kind of grokking those idioms is pretty difficult to like, like using overlays is it's still kind of beyond me. Like, I mean, I've just sort of copy pasted like one thing in my Nix OS configuration. I forget what it's for, but yeah, it's just like stuff like that. It's just, you know, there's, there's a lot of documentation on it, but it's just, it's still kind of like, you know, how do you do it? So, and I guess with a type checker, it might help with that too. All right. So if we don't have any questions, then I guess we can wrap things up. So the agent pug generally will, after the formal presentation and the question and answer, we'll kind of open up the floor for conversation on whatever topic related to the functional programming. So consider, once we do that, we are going to stop the recording and everybody's welcome to stick around and socialize a little bit more and talk about what's interesting. All right. That sounds good to me. I'll stick around a little bit too. Awesome. Thank you for the question. Yeah, thanks. Yeah, of course. My pleasure. Great. Stopping recording now.