[00:00.000 --> 00:07.000] Everybody please welcome Janik. [00:07.000 --> 00:13.000] Janik? Yes, that's me. [00:13.000 --> 00:17.000] Yeah, I'm Janik. I work at FLOX. [00:17.000 --> 00:20.000] Yes, it might be apparent. [00:20.000 --> 00:25.000] I am the author of the NixOS search backend. [00:25.000 --> 00:30.000] And from that and the work we do at FLOX, [00:30.000 --> 00:38.000] we have seen some, well, problems with interacting with the Nix command line as it is right now. [00:38.000 --> 00:47.000] And we have written Runix to make this a bit more nice to use from high level languages. [00:47.000 --> 00:54.000] So first of all this, I see like five different steps in, well, [00:54.000 --> 00:58.000] five different ways of how to interact with the Nix CLI. [00:58.000 --> 01:05.000] The first one might be like the most obvious one, the command plan interface. [01:05.000 --> 01:13.000] That's the Nix program that we know and love or not or whatever. [01:13.000 --> 01:19.000] But I mean, it's commands like Nix build something, develop flakes. [01:19.000 --> 01:23.000] Yes, we assume flakes are a thing. [01:23.000 --> 01:29.000] Copying or like, you know, the list goes on. [01:29.000 --> 01:39.000] But CLIs in this sense is mainly made and done for like user than the user. [01:39.000 --> 01:45.000] So you have completions, you have colors, you have your dialogues and whatever. [01:45.000 --> 01:49.000] But like the main point is everything is very manual. [01:49.000 --> 01:57.000] So every command you do is a single operation and every context you want to share between two operations, [01:57.000 --> 02:00.000] you will have to manage this yourself. [02:00.000 --> 02:08.000] So you will have to manage to paste or write the right and the same flake reference, [02:08.000 --> 02:15.000] installable into two commands that you want to run like together or in the same context or something. [02:15.000 --> 02:18.000] But yeah, it's totally up to you. [02:18.000 --> 02:26.000] So this is where you come and start writing scripts because you don't want to do this all the time. [02:26.000 --> 02:30.000] So we automate with Nix, right? [02:30.000 --> 02:36.000] This is like just writing shell scripts is easy and useful for simple automations, [02:36.000 --> 02:44.000] either NCI scripts on GitHub actions or just local workflows in general. [02:44.000 --> 02:53.000] You can use the same syntax you use on the terminal, you use shell syntax, the same CLI. [02:53.000 --> 03:00.000] But you have now like the CLI has a machine readable output like the JSON output modifies, [03:00.000 --> 03:08.000] allow you to save output, process output and like the bash or shell language that you use, [03:08.000 --> 03:16.000] allows you to compose commands by saving processing and like managing inputs to commands. [03:16.000 --> 03:24.000] Now you have been writing stuff with bash. [03:24.000 --> 03:28.000] Imagine you want to write an actual program. [03:28.000 --> 03:34.000] Now, well, it kind of looks like this. [03:34.000 --> 03:36.000] How do I know? [03:36.000 --> 03:38.000] This is basically what we wrote. [03:38.000 --> 03:45.000] This is part of the Nix search search backend that pulls data out of the flake. [03:46.000 --> 03:57.000] In general, it's great to automate things with flexibility because you have a language around your invocations. [03:57.000 --> 04:03.000] And it is great to build programs on top of Nix using like executing Nix directly. [04:03.000 --> 04:08.000] But it is very heavy on boilerplate as you might have seen. [04:09.000 --> 04:16.000] The structure of the arguments as well as the correctness is entirely up to you again. [04:16.000 --> 04:22.000] And last but not least, there is strings everywhere. [04:22.000 --> 04:26.000] So like you might think like why is this a big problem? [04:26.000 --> 04:34.000] Well, like I guess Doman might agree, people might agree who have ever written apps around Nix. [04:34.000 --> 04:43.000] You end up writing these Nix invocations and managing their inputs becomes a bit of a pain. [04:43.000 --> 04:48.000] So the next step, what's the next step? [04:48.000 --> 05:00.000] For us, it was like, OK, let's remove the notion, the idea of invoking Nix as a CLI app through exact statements. [05:00.000 --> 05:05.000] At least like on the language side. [05:05.000 --> 05:16.000] There are still Nix in the background, but it's done like we put a layer of abstraction on top of it because, well, everything can be solved with another layer of abstraction. [05:16.000 --> 05:24.000] And because I like Rust and we're using Rust now, it's a Rust interface. [05:24.000 --> 05:41.000] So it's typed and we hope to leverage the typing system to, well, create correct, hopefully correct, well, commands and arguments that are also predictable. [05:41.000 --> 05:47.000] So, well, types please. [05:47.000 --> 05:58.000] Let's look at how the Nix eval command looks because the command we saw before was a Nix eval command invocation. [05:58.000 --> 06:01.000] So what does Nix eval have? [06:01.000 --> 06:12.000] If we look at the help or the manual of Nix, we will see like Nix eval has options, like options by itself, and it has arguments that are shared between different Nix commands. [06:12.000 --> 06:23.000] Common evaluation arguments, common flake arguments, and things that change the interpretation of installables or whatever that means. [06:23.000 --> 06:30.000] So, trying to represent this on a high level in Rust might look like this. [06:31.000 --> 06:46.000] You have your flakes, flake arguments, you have your evaluation arguments, source arguments, like the names and the structure is kind of modeled after the C++ code of Nix. [06:46.000 --> 06:55.000] So, to have at least like some guidance here why these are named like this. [06:55.000 --> 06:58.000] Yeah, let's look at the flake arguments. [06:58.000 --> 07:06.000] So, like, flake arguments would contain something like no writing log files, updating inputs, and so on. [07:06.000 --> 07:11.000] So, but why would you care about typing these things out? [07:11.000 --> 07:20.000] Well, ever try to make an input to Git source? [07:20.000 --> 07:33.000] Like, it takes like five steps or so to get to, well, the point where you actually have the right format of the GitHub URL. [07:33.000 --> 07:44.000] And it is a weird format because you have to get to Git plus something and it doesn't work like you would use it on the Git CLI as well. [07:44.000 --> 07:48.000] So, a lot of confusion, a lot of errors as well. [07:48.000 --> 07:54.000] And, like, Nix also doesn't really say why it is, like, what's wrong with it. [07:54.000 --> 08:01.000] It just says URL is unsupported, Git failed, not a valid URL, and you're like, why, what? [08:01.000 --> 08:18.000] So, well, yeah, being able to specify flake references in a typed way would allow you to eliminate an entire, like, class of errors. [08:18.000 --> 08:30.000] Because now, well, like, you can still fail if the repository doesn't exist, of course, but you fail these URL construction classes. [08:30.000 --> 08:39.000] The same thing goes for evaluation arguments here, for example, including things like the include argument. [08:39.000 --> 08:51.000] You have a typo in there, here it's like missing an A somewhere, I don't know if somebody spots this, but the error doesn't really tell this. [08:51.000 --> 09:02.000] And even though, like, the include might be not really necessary with the flakes anymore, but even if you use it, but the idea stays the same. [09:02.000 --> 09:11.000] Then, on the source arguments, like, there's arguments that require, like, a Nix expression as an argument. [09:12.000 --> 09:28.000] It is just a string in every other context, but now we have at least a chance to enforce that it has to be parsed by a Nix parser and has to be actual valid Nix code that is in the argument. [09:28.000 --> 09:32.000] The same is for the arguments of the eval command itself. [09:32.000 --> 09:38.000] The apply argument requires you to parse a lambda, a function. [09:38.000 --> 09:42.000] Like, the error is not telling you this. [09:42.000 --> 09:47.000] It is saying there's an unexpected token and this is not what you want to see. [09:47.000 --> 09:55.000] So, like, enforcing that it is a lambda on a syntax level, that's a step forward in my opinion. [09:55.000 --> 10:07.000] So, this is the, well, typed version of the command that we saw before, and I don't know, for me it looks more clear what's happening. [10:07.000 --> 10:09.000] But I leave that up to you. [10:09.000 --> 10:15.000] Also, like, excuse me, that this is not the exact code that you would write. [10:15.000 --> 10:21.000] There's a lot of ints or some missing, but it had to fit here on the slide. [10:21.000 --> 10:25.000] So, like, it got a bit trimmed. [10:25.000 --> 10:30.000] But, like, yeah, the same concept still applies to Nix arguments. [10:30.000 --> 10:35.000] We saw Nix eval arguments, Nix itself has arguments as well that apply to all commands. [10:35.000 --> 10:42.000] So, they are a bit separate here, but we just allowed input from derivation or disallowed it in this case. [10:42.000 --> 10:44.000] So, we'll do this as well. [10:44.000 --> 10:52.000] Now, we have our Nix arcs, we have evaluation command arcs, and we just run it, right? [10:52.000 --> 11:02.000] We take the struct and there's something that takes the struct and creates a list of arguments and executes command in the background. [11:02.000 --> 11:11.000] So, we take our things, we take a Nix command line back end reference, and we wait for the output. [11:11.000 --> 11:14.000] Why do we take a back end reference? [11:14.000 --> 11:22.000] Well, Nix is, like, calling out to Nix is great, and it will serve our purpose for, like, the time being. [11:22.000 --> 11:24.000] But what do we do? [11:24.000 --> 11:31.000] We take data, we put it into a struct, and we take the struct and we put it into strings, and then we put these strings to Nix. [11:31.000 --> 11:40.000] Nix takes these strings and creates a struct, evaluates stuff, do stuff, serializes it back into a string. [11:40.000 --> 11:42.000] We deserialize it in RAS. [11:42.000 --> 11:45.000] There is a lot of serialization back and forth going on. [11:45.000 --> 11:55.000] I think Jan talked about this earlier with his Nixle, and yeah, like, why do we need all this back and forth? [11:55.000 --> 12:05.000] Well, one, this kind of raises the question, like, okay, the next step, wouldn't that be like a truly native back end? [12:05.000 --> 12:07.000] So, what's next? [12:07.000 --> 12:19.000] Well, we might expand on the Rost FFI bindings and therefore allow for, well, more efficient commands because no serialization is taking place. [12:20.000 --> 12:36.000] We allow for entirely custom commands, and with custom commands, well, you could write a wrapper around Nix. [12:36.000 --> 12:48.000] You could write a new or experiment with a new Nix front end, and maybe you could empower Nixle if we built the bindings in the right way. [12:48.000 --> 12:57.000] And in the end, it is modular, so, like, the entire library is built on top of the idea that you implement commands rather than, like, a back end. [12:57.000 --> 13:10.000] So, you can implement commands for, or, like, you can implement different back ends for a command, and yeah, do all this step by step. [13:11.000 --> 13:16.000] Now, for some less ambitious ideas, what can you do with these things right now? [13:16.000 --> 13:23.000] Well, you can still build custom Nix front ends or use Nix in the back end and do stuff with it. [13:23.000 --> 13:25.000] You ask me how I know. [13:25.000 --> 13:36.000] You can build testing or mock back ends for, like, well, integration testing or unit testing in, like, confined environments. [13:37.000 --> 13:43.000] Or you could implement a dry run function, and this is my community pitch for today. [13:43.000 --> 13:49.000] Use, you could use something like your Nix here and write Nix explain. [13:49.000 --> 13:58.000] It takes all the arguments of Nix, but the output is not something that Nix does, but just a description of what this command is supposed to do. [13:58.000 --> 14:00.000] Just an idea. [14:00.000 --> 14:05.000] So, and this is my second to last slide. [14:05.000 --> 14:13.000] I talked about a lot about, like, replacing the Nix front end or replacing anything in Nix days. [14:13.000 --> 14:18.000] Like, we also, like, here don't intend to replace Nix in any way. [14:18.000 --> 14:34.000] This is entirely trying to make the user or the developer experience for people who are using Nix inside their applications more convenient by providing the proper layers and proper bindings. [14:35.000 --> 14:48.000] We might, like, explore ideas with Nix developers, maybe TVX people, to see whether there's, like, bindings to be made and in which way. [14:48.000 --> 14:55.000] But for now, we are focused on empowering people. [14:55.000 --> 14:58.000] With this, thanks for your attention. [14:59.000 --> 15:01.000] I'm Wysander on GitHub. [15:01.000 --> 15:04.000] I have today published the crate for it. [15:04.000 --> 15:06.000] You can contribute if you like. [15:06.000 --> 15:10.000] And Flux is hiring, I guess. [15:18.000 --> 15:22.000] So, we'll only be able to take one question. [15:22.000 --> 15:24.000] You have one question. [15:24.000 --> 15:25.000] Two questions. [15:25.000 --> 15:27.000] Let's go. [15:27.000 --> 15:31.000] Yeah, I love the idea of native interface to Nix. [15:31.000 --> 15:40.000] Do you think, I mean, do you know how, if it would be hard to keep up with, I mean, isn't it, I guess you want to give it back on this interface? [15:40.000 --> 15:41.000] I'm sorry. [15:41.000 --> 15:43.000] Is it stable in any way? [15:43.000 --> 15:48.000] How would you think if you could maintain this at the set of five? [15:48.000 --> 15:51.000] Currently, it's in the ideas. [15:51.000 --> 15:53.000] Oh, sorry. [15:53.000 --> 16:02.000] You can answer the question and repeat it. [16:02.000 --> 16:04.000] Okay. [16:04.000 --> 16:18.000] So, the question was, like, how stable are the Nix interfaces to which we will, like, bind to and, like, which stability do we expect from those bindings? [16:18.000 --> 16:23.000] At this point, like, binding to Nix natively is more at the idea stage. [16:23.000 --> 16:35.000] And we have seen, where we have seen examples of this in, like, the, what is it, like, the harmonia lip store implementation. [16:35.000 --> 16:42.000] That is, that probably, like, provides lessons to be learned from. [16:42.000 --> 16:45.000] For now, this is something we will, like, experiment. [16:45.000 --> 16:47.000] We can try it with, like, like, individual commands. [16:47.000 --> 16:51.000] We can try it with, like, custom commands that we implement. [16:51.000 --> 16:56.000] But, like, for now, it's not clear, like, how that works. [16:56.000 --> 16:58.000] Thank you again. [16:58.000 --> 17:03.000] Thank you very much.