 where it's probably closed source. Pick all the problems out of the way. So in the early days, OPAM often had to be built from sources. Now it's present on most OS package managers out of the box. So I'm going to do the demonstration that's mostly on Ubuntu, which hasn't yet updated to OPAM 210. But fortunately, our very own ABSM maintains a PPA. So we're able to switch to that. So I'm just now going to share my screen, hopefully. Yes, right. So this is an Ubuntu vocal installation. So it's 24. It's the current LTS. And as I said, OPAM is available from its package manager straight away. Doesn't take terribly long to pull up and install. It's probably familiar from CI systems, if not from your own systems. And once that's through, the only slight problem that we get is that that is 205. So very quickly, we'll do a live upgrade to OPAM 2.1. And we pull in this one. Hot off the presses. And hopefully this time, switch to keyboard. So apparently I can't type in it. There we go. So we're now at OPAM 2.1. So I don't know how easy it is to do a show of hands. I imagine most people here have probably used OPAM. For anyone who hasn't, OPAM requires you to begin by initializing it. So it won't do anything until it's been started up. And we do that by issuing this OPAM in its command. At this point, it's contacting a web server that downloads a table copy of the latest OPAM repository. So it's pulling down the package definitions. That's quite fast. It's then processing them, bringing them into create what we call an OPAM route. So which is a collection of your OCaml installations and the information that's known about the metadata. Once that's complete, I have actually already initialized this container. So OPAM, as well as maintaining installations, attempts to be a shell wrapper and a management tool for being able to use commands and things distributed through it. So it has a lot of shell integration. As it happens, it's already set up. So I shouldn't say no. And then the exciting part, which the eagle-eyeable spot is new in 2.1. OPAM then goes on to create an initial switch. Because the primary aim of OPAM in it is to get you to be able to run OCaml. And at this point, it puts this new thing called a switch invariant together and constructs a switch. It detects that I have OCaml 481 as a result of the Ubuntu package that has it there. And it's now set us up. So it tells us to run this little run in order to update the environment. And we can then see that it's added something to my path, as well as doing a few other bits and bobs. But now means that I should be able to access binary files that I installed. And it's installed a small handful of packages. So that's the very first opening into OPAM. Its main purpose, right since 1.0, is to be able to create lots of different switches. So at this point, I can then create a new switch for my project, if I wish, with a little room that goes together there. And it creates a second switch for me. As it happens, even in here, there's another feature that's new in OPAM 2.1. That command itself wouldn't work in OPAM 2.0, but we'll come back to that in a bit. So here I've asked OPAM to create a brand new switch. I've given this a name. And I said, would you please put OCaml 481 into it? And as a result of the fact that the system has got OCaml 481 installed by the OS package manager, it's quite a fast process of doing it. I run the room again, and we can then see that it's updated path to point to the new path. So far, so good. And we now have two switches in our OPAM route installation. Now, building our OCaml compiler takes quite a long time. So I prepared a few earlier, if you will just forgive me. Resetting my route. So now I have the same setup as I had before, but I've also built OCaml 4, 2, 5, 11, 12, and 13. On top of that, OPAM isn't just for managing your switch installations. It's also about discovering packages, being able to mine information about packages, and so on and so forth. So OCaml comes with a rudimentary top level. There is a slightly better one. We have the ability to search for a package. And we can see here's Utop. Why didn't we install that? At which point, OPAM starts carrying out its main job. We can ignore that for the time being. It's just an artifact installation. So at this point, OPAM is now working out exactly what needs to be installed in order to get this package Utop that we requested. And it's now come back with what it thinks we're going to do. It says, I can give you Utop 280. And I'm going to do all of this stuff above as a result of doing that in order to satisfy it. So we let that run through. It's relatively fast. Another OPAM 2.1 thing that we've worked on, which is subtle, but it's actually downloading and building things at the same time, which if you're downloading 300 packages is kind of useful because it does mean that it starts building dune within a few seconds of beginning. And it does prioritize the downloads based on what's earlier in the dependency chain as well. So in fact here, you can see there were packages being installed before it had even retrieved everything that needs to be done, even when it was using the cache. So at that point, it's finished the installation. And we have Utop. So far, so good. Then we can go back to a previous switch. Don't need to follow the runes because I've allowed OPAM shell integration to automatically update the path. And I try to run Utop again. And it says no because we've left that switch. It's completely isolated from the rest of the shell environment. And that's the end of that. OPAM gives a nice little hatch. You can actually choose to run commands from other switches if you want. So I can run my project and then pull up Utop from within that switch and bring it back. Then on top of that, if we now look at, for example, OPAM show Utop 280, we can see in the description that Utop is for our camel 403 and later. So again, the solver works as it's supposed to. If I go to a much older switch, it's our camel 402 and ask OPAM to do exactly the same thing. It's OPAM's job to figure out how to make that happen. So it will go through all of the previous versions, figure out which packages are required, and eventually the solver takes a little bit of time to come up with this with the older packages because there are too many things to consider. It comes up with a solution that is actually given as Utop 2.2 in this instance. I'm not going to let that go ahead because that will take a long time. So that's a very brief introduction to OPAM, but I hope there's not too much of a surprise. OPAM also has the ability to manipulate additional repositories. There are admin commands for updating those repositories. There's a whole subsystem for pinning packages to specific versions or to working on actual development versions themselves. And you can have local switches where you put a switch inside your repositories, everything else. But that's all in OPAM 2.0, which was released in September 2018. OPAM 2.1 was released last summer. So we'll just this summer just gone. So in that meantime, there's been quite a large passage of time. Let's have a dive into some of the things that we've actually worked on in OPAM 2.1 in that intervening nearly three years. So everything that we've added to OPAM 2.1 has been about improving the quality of life for using OPAM, at least trying to. So we have either been trying to make things faster, more reliable, easier to use, or preferably, all three of them at the same time. I think one of the biggest places where that's noticeable is in switch creation. So way back in 2018, when we released OPAM 2.0, the largest change relative to OPAM 1 was that the compiler ceased being a special case. So in OPAM 1, there was a lot of special knowledge baked into OPAM, a special package format that allowed you to specify OCaml itself. That got removed. We added enough features to OPAM 2 to mean that it was just a normal package like anything else. The problem is that the way that was implemented has leaked out to users and is a little bit of a usability issue. You have to pick between, as you may know, OCaml-based compiler, OCaml variants, OCaml system. You have to remember what they mean. And we've now got it to the stage that most of the time, you should just be able to say, I would like OCaml, please. And there's then the work that's been done in order to facilitate that happening, then actually means that upgrading OCaml in a switch should be considerably less painful than it was before. So going back to an example, if I switch to an OCaml 412 switch here, this switch has got OCaml 412-0 in it. So maybe it's one I haven't touched for a few months. And it's got U-top 270 in it. So again, that probably fits with the release earlier this calendar year of OCaml 412. In OPAM 2.0, the precise runes to move this switch from OCaml 412-0 to OCaml 412-1 are rather difficult to remember. And they're extremely unreliable. I'm very pleased to say that in OCaml 2.1, we have dealt with the unreliable. We will only aim in future versions to try to deal with the memorability of it. So in OCaml 2.0, the core concept of the switch was that you had a list of packages. And there was a subset of those packages that we regarded as the base of that switch. And those packages, whenever you were installing something, were fixed. So they were not permitted to be changed. So in OCaml 2.0, OCaml-based compiler at version 412-0 would be regarded as the base of this switch and that cannot alter, which is fine. Usually that's what you want because otherwise every time you install or upgrade, your switch would attempt to meander towards the latest released version of OCaml. The problem was what happens when you actually wanted that to happen. So we've replaced base packages completely in OCaml 2.1 with a new feature called switch invariance. Sorry, wrong command. And the idea behind this is instead of having a list of base packages, we have a package formula that describes exactly what the switch needs to satisfy in its base. So in this case, rather than saying the switch consists of OCaml-based compiler 412-0 with all its dependencies, we just say we would like the OCaml package to be between versions 412-0 and not 413. So in other words, it specifies the latest release within the 412 series. And having done that, it means we can actually just say OCaml upgrade at which point we let the solver do its usual work. And we can see here that it's going to upgrade OCaml 412-0 just to 412-1. So it's not meandering into 413, it's certainly not installing trunk and installing a development version of OCaml. And on top of that, it will upgrade the rest of the switch at the same time as part of a normal package. So UTOP will get upgraded, it will all be built into the same sole. So the idea is it's easier, fewer invocations of OCaml and it actually does what we need. It gets even better when we start looking at using system compilers. So I'm going to switch, hopefully, successfully to another running container and show what I think can best be described as a car crash with OCaml 2.0, which I hope isn't too familiar. So this is a focal container that I've upgraded to here, suit. So it's OCaml package installed by apt has changed from OCaml 481 to OCaml 411-1. OCaml, on the other hand, hasn't yet done anything. So when I run OCaml list, I get the strange message at the top, but at least alerts me to the fact something's wrong. OCaml's system has disappeared from the list and it's not quite clear what's happening. If you try to install something, OCaml would then play a bit further. So, okay, I'll run OCaml upgrade. Let's see what happens. We get that error again or warning again. The solve was doing a little bit of thinking and then suddenly we get a whole series of strange-sounding error messages that do mention a few things called base packages and some other strange things going on. So maybe at that point, I don't know you've gone to discuss, you've gone to forum somewhere else I'll see and somebody says, oh, maybe you need a unlocked base or something. You start to hear about this very strange option that you've never come across before. So you attempt that and OCaml goes away and thinks about it again. And this time it comes back with an answer, but the only problem is it's not the answer we expected because we know that the system compiler on this computer is 411.1, but it's going to upgrade us to 413.1 and it's going to build it from sources. So that's not what we wanted either. It turned out that the actual room to correctly update the system compiler is to explicitly install that system compiler like that. And finally, on this up, I would say really quite unmemorable command for something that maybe needs to happen every six months or so. You actually get the upgrade that you expect from 4.8.1 to 4.11.1 and it's actually reinstalling the OCaml system package because it's removed it. Let's see that in OCaml 2.1, so just two. We are now switched to 2.1 now. 2.1 there. We do OCaml list again. This time it's not complaining at us. We only asked it to tell us what was in the switch. So OCaml is slightly more polite this time. It doesn't look into the problem of the package. So we can see that OCaml's view of the world is that it's OCaml system 4.8.1 that's in that switch. And now we simply say OCaml upgrade. Now it identifies there's something not right about the OCaml system package. It says, I need to reinstall this. What happens next? And we get exactly the correct answer first time from just a normal OCaml upgrade. And we need that B for the time being. Other things that we've been doing have been improvements to the ability to access alternate versions of the compiler. So compiler options. You might have seen this if you've been following the announcements of Alpha and Beta releases of the 4.12 and 4.13 OCaml compilers. So in the past, if you wanted an F Lambda switch, you had to remember that that meant you needed OCaml variants dot version of the compiler plus F Lambda. You had to hope you didn't want any other options to go with it that hadn't been thought of. And you also needed to create probably a fresh switch into it. So this feature with the switch invariance now means that instead, you just say, I would like OCaml option F Lambda please. And you can add it to an existing switch. At which point again, Solver doing a little bit of work. OCaml then reply back saying, look to that. And at this point says, I just going to need to rebuild, that's fine. So it switches automatically from the old OCaml based compiler, which means unaltered vanilla sources. It switches to an OCaml variant package that you need to specify at all. It installs the option you did and then says, well, the whole switch is going to be rebuilt. And that again would happen automatically. Skip that in the interest of time. And you can do that in switch creation. So again, here I start my terminal is wrapping very oddly, which is remote desktop windows terminal and I wouldn't want to blame. But at this point, I'm actually creating just about see it, a package where I've said, give me your OCaml 4.13.1, it's impossible to specify an OCam 2 thing and give me F Lambda and it will then go away. And so immediately infer the switch invariance that corresponds to that package list and the one version constraint. Oh, oh. Oh, I can't type. It should be OCaml option F Lambda. Students, Professor Jay Abernethy here again on the 12th floor quota, got Spring Street behind me. I'm going to try something different today. We'll surprise for you guys. Doing a lecture with an actual physical way for it. What do you think? Nice and clean. Let's do some teaching on it. So today we're going to talk about graphs. In fact, for the next several lectures, we're going to discuss graphs. As you already know, graph G is a set of vertices. There we go. And we can actually see the compiler if I can talk over an invader. The compiler is now going ahead and actually building a 4.13 switch. So that then works very nicely. You can specify the options you want. You can put them in the invariance so you could have a switch that must be a 4.13 switch and it must have F Lambda. So that's switch creation. Another area that we've done an awful lot of work in is dep exits. So up to this point, we've been talking about pure op-amel, but eventually we get to the stage where we need some C things. We need something that comes from the else that comes from the OS package manager. So opam one had a dep X plug-in. In fact, plug-in architecture, I think was added in opam 1.1 and that carried on into opam two. So the idea was to have a command that you could pass the list of packages you want to install. And the plug-in would ensure that your OS package manager was up to date. So for example, we could then say another quick switch in opam 2.0.9 on this Debian container. I could then say opam install MySQL. Little bit of thought gives us a solution, but very quickly that goes wrong because the system package is missing. So the idea behind that is that we then say opam Debian MySQL in 2.0 world. It says, oh, the plug-in I need to download, which was done largely for maintenance because it let the plug-in could move more quickly than opam one necessarily did. It then goes on to look at what's on the package manager and says, ah, there is a system package missing. May I call act? Which point give opam permission to do so. And that's it. It now downloads and installs that. Then we can go back to what we were doing in the first place. And finally, we can install MySQL. So there's a few problems with that. We'll get there, but we had to issue a lot of commands. It is possible with flags to turn it into one command. You can tell the depex command to go on and run the opam install, but even when you did that in opam 2.0, the solver is still called twice. So if you had a particularly complex package set to install, then you're fundamentally wasting a lot of time. And even worse on top of that, the solver could return different answers between these two solutions. So it is entirely possible, depending on how the package repository is set up, to be that the packages you install the depex for, it then selects different ones, which you haven't installed the depex. So your CI system then fails. And when I say your CI system fails, I mean opam repositories. CI was quite capable of picking that up as was GitHub actions and all camel CI and various other systems. So it was a serious issue that had to be worked around. On top of that, it meant you couldn't depend on system packages and what was already there. So for example, if we look at the actual definition of the MySQL bindings in opam, it actually doesn't need MySQL, it's capable of using either. So we can have MariaDB or MySQL. So if we just quickly restart that container, and this time installed by hand, MariaDB library, the bit that's annoying at this stage, is that when I install MySQL, it will still ask me to install ConfMySQL, even though MariaDB is there. So the only way in opam 2.0 that I could get around that is actually to explicitly say, give me Conf MariaDB, give me a word, I will tell you what it is I want you to install at that point, which point says, oh, okay, I can do that. And that will then work straight through. So similarly, in opam 2.1, we've got rid of that plug-in completely. The whole thing has been integrated into opam itself. So now you issue the same rune to start with, the solver comes back with an answer eventually, still with ConfMySQL, but that's just fine. This time it immediately says no additional solving, it already knew this, there's a depex missing, would you like me to install it? Say yes, let's go ahead with that. And then it goes downloading and that's going to carry on as normal. Now similarly, if I restart this container, when opam catches up quick restart on that one, this time I'm going to do, just as I did in the 2.0 version, the headers in manually. So we now have a system that is capable of linking against MariaDB. This time when I say opam install my SQL, not only do you have the nice integration of the depex, but opam will automatically say, oh, this depex is there. That means that this is a better package to choose than the MySQL one. And it's actually offered me ConfMariaDB straight away. So I can go ahead and do that and it will much more quickly get you the package you requested based on its constraints. Having done that, there's nothing that stops you. And just wait while it catches up with me. There's nothing that then stops you saying, oh, actually I did want MySQL bindings as well. And I can do that afterwards. And as opam normally would, it will then say, okay, that's fine. I need a depex for that. And I'll need to recompile that package but then everything will be satisfied. And just as before, it's still asking for the same part there. So I say, switch creation, depex, I would say are probably the two, they're certainly the two features I wanted to demonstrate today. I got to talk about some of the other ones instead. So I just stop the screen. Chef now. So what else did we do in opam 2.1? There was in just the same way as we integrated the depex plugin, there was also a plugin for creating lock files. So that's where you take the current state of your switch. Your project say, I want the exact versions of these packages specified, write it to an opam file so that I can commit that to my repo and then share that with other developers or just say, this is a known less configuration. So that's actually been in existence since opam 2.0. The facility to create switches based on it was always there. The plugin to create the lock files, sorry, the facility to create the lock files was itself a plugin and we've simply moved that in and blessed that as being a supported opam feature in 2.1. One of the things that delayed the release by longer than would have been nice was that we discovered after the fact that opam 1 to opam 2, although it took three years, was actually easier than going from 2.0 to 2.1 because the main thing that we were able to do with the 2.0 rewrite was to throw away opam 1. So the package repository was automatically rewriting for requests against one were mirrored to another. We didn't have to worry about backwards compatibility of the formats. We just make sure that the packages could be mechanically upgraded. And don't get me wrong, it was a ton of work, but we didn't then have to support opam 1.2 afterwards. We were just redirecting to an old repository and it was sunsetted a couple of years ago. With opam 2.1, they're kind of both out there. Both binaries are there. They have different command lines. So there are two or three features that we then added. The initial name for it was CLI versioning. So command line interfacing. It's a feature that I have no problem saying we mercilessly corrupt from dune. So it's inspired by dune's lang dune stanza in your dune project files. And it just says, if we could have a way that the opam command line knows which version of opam you expected that command line to work for, then we can make your scripts rather less painful in the future. So to give an example, again, I'll turn the back up, come back to this one. If I issue that rune going back to opam upgrade minus unlock base, opam now hopefully says to you straight away, that's not correct. It's not called unlock base anymore. Gives you a clue about what the new version of the command line is. And it tells you what you need to do in order to run that way. So what we now have, if you want to have commands that are compatible with opam 2.0, is you just set an environment variable before doing it. So at which point it now says, oh, I'm in 2.0 mode. I know what that means. It still means translate it to update and variant, but opam can do it automatically for you. And it then offers to upgrade the switch, which we'll skip for now. Similarly, it also provides a way of guarding yourself against using new features you didn't mean to. So if you have opam upgrade there and you try to use the opam 2.1 command for it, it will then say, no, that doesn't work because that's available in a newer version. And so it gets rejected. So that went all the way through. And so the whole of opam, we have it for enumerations. It's for environment variables. There are warnings if you attempt to use newer environment variables that have no meaning. And so opam 2.1 would say, if you cheated and said opam update and variant equals yes in the environment, it would still say, I've ignored that because you requested opam CLI 2.0. And so it's had no effect. Similarly, we'd actually had various plugins and other utilities were appearing that were using opams libraries to manipulate the state. And again, this had been fine while we were in opam 2.0 and everything was compatible. But the changes, especially for switch invariance meant that the opam routes been upgraded. At which point, nothing works if it uses the 2.0 libraries, which seemed okay to start with, except that it was far too easy to end up in situation that software that your commands had installed the switches just stopped working. So we actually have applied the versioning even back into the route. Opam, I can't think of it just cheekily look as one should never look in the internal files of an opam switch. So in fact, we're in the past, all of these files just would have said, oh, my opam version is 2.0. It still says that, but it's added an extra field below to say, but I've been written by opam 2.1. And the opam library, version 2.0.9 of the opam libraries that were released understand that. And what they will do at that point to say, I can read the switch and I can't write it. And so we've introduced a mechanism from 2.0.9 onwards as a compatibility step that actually allows you to write plugins that read opam state directly, that will carry on working all the way through whichever versions of opam become in the 2.0 series. And then similarly, other under the hood changes, all on the interest of making things faster. I already mentioned the interleaved download and build, which I think is possibly one of the, maybe one of the least noticed, but most appreciated features of opam 2.1, because it does simply mean that opam install is actually considerably faster, even without parallelism. There's also a trick that Louis Guespo implemented a year or so ago, that opam update has tried to become a little bit faster by instead of storing a flat check-out of all of the opam repositories you've added, it keeps them tarred and tries to use to make it faster. And on most systems, that's had the effect of making opam update a much faster operation as well. So yeah, things to come. We are not wanting to spend three years working on opam 2.2. The plan is to release opam 2.2 early next year. Some of the features that are slated for us at the moment, there's a feature called subpath pinning that was in fact implemented for 2.1, but it didn't quite make the cut. So the code is in opam, but it's completely disabled. That's the ability to pin a package, but using where the package resides in sub directory of the repository. That's been polished off and turned into a full feature for opam 2.2. In just the same ways, we've got a CLI versioning technique and our opam root versioning. The next stage that we want to go to is to be able to do that with opam files themselves because the features that we need for opam 2.2 actually involve changing the format of repository package files. Now, that was another issue that we escaped in opam one because we just skated over it. We just said, well, that's fine, we're gonna do an upgrade. So the aim here is that we will introduce a plugin that the old versions of opam will be able to use and say, I've been given a file that's opam 2.3. Would you please give me something that's for opam 2.0? And the plugin can then make the choice either if there is a mechanical way of rewriting the file, which for some of the features that we're adding, there really are, there could just be more commands that you can pattern match and interpret, then it will rewrite it in a way that opam 2.0 can accept. And if not, it will just get rid of the fields that aren't going to be recognized and put available false at the bottom so that you have a package repository that may be for opam 2.2 or for opam 2.3, but that can still be synchronized with by opam 2.0. And the decision then is as a package author that you've decided, I don't want opam 2.1 users to be able to use this feature anymore. We're also adding finally, Assembler operator. So that will deal with the last part of switch creation where I said that the runes for upgrading would become more reliable and Assembler operator should also make them actually easier to remember because you will just be able finally to say, I would like OCaml 5 in my storage please. Just write that. The elephants in the room is window support, which I tried to hint that I do something about that by using Windows terminal to show the previous examples. It is finally landing in opam 2.2. Andreas Hauptmann's Herculean effort to keep an opam repository MinGW going has been fantastic for the last five years. He has indicated that he wants to sunset that repository. It's finally given us the proverbial kick to get the OCaml-based compiler packages in upstream opam repository into gear and working correctly so that you can use Windows opam and use upstream opam repository. And on that as a final piece of the demonstration, we're also looking at integrating fast opam switches into opam 2.2. So this is some work that I've been doing with my OCaml core developer hat on where we're trying to allow switches to be cloned more quickly so that opam switch creates. So that I could do a demo like this, hopefully in six months time and actually show the switches being created as opposed to saying, we'll skip that now because that would take too long. So here, as you can see, this is Windows Docker running and it's running a slightly custom build of opam 2.1 that includes shell integration. I've created a profound project that is just there, but as you can see, it's using a function from OCaml 4.13. So I think, oh, okay. In this opam route, I've got these two switches that are special versions of OCaml at the moment, the test back ports of a series of patches that are called relocatable. So at the moment it's on OCaml 4.12, I can say, right, give me a switch please. Give me 4.13.0, opam is going away, thinking about it just as it did before, quite quickly on this particular one. So at this point, opam is detecting the installation of Visual Studio in the stock container. It's latching down where the Microsoft C compiler is. Their scripts on this particular one are slow, not mine. Once that's latched, it's then looking for another OCaml 4.13 compiler with exactly the same configuration in the opam switch. And at this stage, it now copies it, which means that you have nine seconds for opam switch creation with an entirely fresh opam switch with a compiler inside it. So with an OCaml 4.13.0. So the hope is that that might land, it's not clear if it'll make it for 4.14, it may be that it's at some point around the 5.00 series, we can see how the back ports are going. But the hope is that fast opam switches will also be coming somewhere soon to an opam root near you. And I think that's possibly a good point for me to stop talking. Okay, thank you so much. This was great. Learned a ton. This was wonderful. So I wanna open up the discussion. First questions about opam for David. Just unmute yourself and ask. Great presentation. I have three. Maybe I'll just start with the easy one. I really like how in the OCaml open source world, you depend on a package and you run into a problem and then you can just kind of say, okay, opam source package, save it here, add debug statements, rebuild against it pretty easily and then see what's going on and then further get sucked into upstreaming the fix. Which is pretty great. I feel like I might be doing pinning wrong because that workflow is like a little bit difficult. Like let's say I have a package, I opam source download package name and save it somewhere. And then I say opam pin add package directory where I saved it. That process where then I like go to that directory and add a debug statement and want to rebuild my whole project against it. I feel like I have to do then opam pin remove foo and then it says, okay, removing then I'm rebuilding what the standard one and then I have to do opam pin add foo directory and do that over and over again. Mike, is there a faster way to do this? There is, I would say that the answer comes in two parts, opam upgrade foo. When foo is a pin, this is sort of the strange remembering the precise route, opam upgrade foo when foo is a pin will refresh the cached copy of it and then recompile the switch. So that's, however, I have to say that we're moving in a direction that tries to avoid using pins for development in as much as Dune's vendering is better. For the pin, essentially, it's sort of a hybrid of the two so that you'd start off when you're working on a fix because chances are you ended up then needing to look at something else that needs fixing as well. I did a blog post a few years ago where the fixtures were across three Mirage libraries at which point opam pinning is, well, frankly, horrific because you're just having to remember to keep all of these pins up to date. And the reason it's horrific in opam is because really it's the job of a build system to do that when things have changed, not a package manager. And so I think the nicer way moving forward is that we use Dune to develop the patch, but then once you've got the branch and you want to test it against other things, of course, you can push that new branch somewhere or you could just pin to a git branch that you're not expecting to do development work and that you just now want to see our other packages work. So we can end up with a hybrid approach from the two. But yes, opam upgrade is the main answer to a question. Yes. Awesome. Thank you so much, time. Thank you. Well, there's more questions. Everybody nervous. Or nervous as to who's going to speak next. David, it might be worth showing Michael the way that we did the sub modules in Ocurrent as an alternative pinning. Because that's a big illustration of the git workflow. So this example, let me fire up a browser. Now, can I, of course, now zoom on my desktop is being strange. Oh, there we go, share screen, got it back. I can share. So one of the projects that we maintain or have written at OCaml Labs is a builder for Docker-based images. So I just share this part through. So this is, can I make that a little larger? That's too large. This is a system that once a week or whenever we want to get off, we can say clone opam repository and it goes away and then builds a huge number of Docker images containing OCaml, images.ci.caml.org. And these images then are built. So you've got, for example, Debian 11, and then you expand into it and it's got various permutations of OCaml. And all of them then get put into multi-arch images and uploaded to the hub to OCaml slash OCaml. And the primary purpose of these is that they sit as the base for the CI systems for OCaml repository and for other OCaml projects. The maintenance trick that we use for those rather than having to do OCaml pinning is to see each one of these has got different components held at different sub-module versions. And the nice thing that Git adds with that for the workflow is that when I make, we have to change the base image builder once per month, either with new distros or with Microsoft give a new cumulative update each month and that information comes in. That involves a change in certainly OCaml Docker file. So this sub-module is here as well as in the base image builder itself. It is possible to develop all of that in the same work tree. You actually start the PR from within the sub-module and having pushed the PR up to the OCaml Docker file repo, you can also commit the sub-module change in a PR on Docker based images and GitHub allows that to work. So you end up without dangling branches that you, or dangling, sorry, often commits that you can end up with a normal workflow. So in fact, yes, we occasionally have trouble remembering to ensure that the PRs have actually been merged. But yeah, the sub-module way is another nice trick for that. Other questions? Talk a little bit about governance and security on the package repository itself. I know NPM had a problem where someone removed something and then the main repository had a problem where someone added a malicious or faux malicious thing. I'd just love to hear a little bit about how that's managed. Okay, there's a few parts to this. So we've never removed a package. In fact, there's general policy and open repository if you don't remove them. Unfortunately, that's making the solver slower and slower. So it creates the need for more innovation to deal with that. What we do do if there's a package that's actively broken is that the package remains, but it gets changed to available false because at least that is a better error to give to a user. For actually protecting users, Opam by default is sandboxed. So all of the builds run within bubble wrap. That, I have to say, is done from the view of protection from accidental error. That spawned from an error in a make file a few years ago for anybody who was using Mac OS and by apologizing if he was stung by it, that Opam issued accident or a packages build instructions caused Opam to issue RM minus RF slash. And it turns out that on Mac OS, that is not guarded. And so as a result of that, sandboxing was very quickly added into Opam 2 at one of the mid-beta stages, which is why it's there. So that protects it, but I have said that doesn't protect against malicious operation because at that point, it's got read-only access to your entire system. Although in the build network access is denied, I wouldn't rely on that to stop exfiltration of information. So it's still very much trusted. What we're doing beyond that, or what we're doing, what Hannes Maynard has been doing for the last few years is that there is work in progress to have trusted updates to Opam repository where right from the package table, all the way through to the metadata in Opam is signed in a mildly complicated system but that allows it to be that it's signed without a single source of trust is the reason for the complexity. So it allows Opam repository maintainers to be able to edit important metadata such as the constraints or descriptions without requiring new signatures and it works with a core of signatures. So we're heading in a direction where the codes that you actually install has been signed from developer right the way through repository and onto the computer. But I'm not totally certain when that's going to land, is the only caveat. Of course, just to follow on to that, if there's a package that's been abandoned, okay, it was last update in 2015 and now someone wants to do a new version that uses standard live instead of pervasive or whatever it is. Is there a mechanism that can get taken over or is it just create a new name and try and convince everyone to switch? At the moment, present day, that just happens when you just decide to do it. So there's no thing at all. For the update framework work that's being done for that, yes, there is a mechanism of achieving a core and to hand over a new key. And it just requires a number of repository maintainers to commit to agree to that change and then new keys are issued. So yes. Sorry, there's nothing at all now. So in other words, I could upload a new version of something, even if I am not the original uploader. Yes, that's correct. So I say that you would open a pull request to our camel.com repository and it would be rejected, but it would be a human that would be verifying that and I have to say it would be rejected and very occasionally errors do so through where it's like, ah, but again, it's not happened maliciously at the moment, it's happened by accident where somebody's used to name and discover that it happens. Normally what would be caught on open repository is that the CI testing would spot it because of course you would effectively be uploading a new version of something and it would then attempt to build all of the reverse dependencies of that at which point the world is likely to end for that CI run and it would have said, what's going on here and say, oh, this isn't a new version of the same package. So it's not a problem that we've hit very often so far. I can think there was one case in the last year, I think of the name where somebody did have to go away and bench said, ah, new package. Thank you. I think I'm gonna stop the recording now and then we can continue talking, but I'll stop that now.