 Hello everyone. My laptop says that it's 4.50 a.m., which means it's time to start this talk. I might be on the wrong time zone here, but I'm really excited to be at the Zephyr Developer Summit, part of the embedded open source summit, and talking about Zephyr Manifest files. If you take one thing away from this, I think you should have it in your mind that manifest files are a great way to manage revision control in your Zephyr applications, and I'm going to keep hammering on that topic while also dancing around the different things that you can do with manifest files. So today we'll talk about what those files are and how they work, why you should use them in your project repos, and how to set them up in your project repos, kind of the next step after you have the basic project, like what you want to start adding to your projects, and then I'll close out with things that we don't have time to talk about, but you should have some idea of what they are. My name is Mike Stisch. I am a developer relations engineer at Goliath. I have been fascinated with firmware for at least the last 15 years, and previously may have known me as editor-in-chief of a hardware-focused tech news site called Hackaday.com, which is a great place to go and learn about how to misuse hardware and kind of what new stuff is coming down the pipeline. But the company I currently work for is called Goliath. We are an IoT cloud company, so we like to say it's your instant IoT cloud for micro controller level devices. We kind of that scary area between hardware engineers and cloud engineers. We kind of bridge the gap there. And one of the things that is important to us is that you should be able to use your own hardware for Internet of Things. You shouldn't be required to buy a company's hardware and use it. And in order to support that, we really depend very heavily on Zephyr because it has the ability to build projects across Silicon for many different vendors. But one of the things that we kept running into is, as a totally remote company, is this Zephyr project going to build on my computer and my colleague's computer and is it going to build on our customer's computer? And I think even more importantly, like for Zephyr Developer Summit last year, we spun up a bunch of demos, hardware demos, and Zephyr was at like version 2.7 back then. And I was at version 3.5. I guarantee none of those demos will build if we just pull Zephyr up to 3.5 and don't change the code. And that's a real problem. And so we really wanted a way to lock each of our code repositories to the specific snapshot of Zephyr and all of the modules that they use. And so that's what manifest files do. So it really is like a package management system. It has a hierarchy for each project. The core part of those hierarchies are repositories. And those repositories are going to have an actual location of where to go check out the code. They're going to have a revision, which would be like the branch, the tag, or the hash number for them. And then a local path on where to check them out. And these are very simple things. But if you use them in the right way, it kind of magically makes this build environment come alive. We'll see some of that in a little bit. And the best part of them is this is like a human readable file that you commit to your own code base. Now if you want to meet me afterwards, I will talk your ear off about how much better manifest files are than the get submodule command. Like for instance, if you've ever set up a get submodule for a fork of a project and then you're like, oh, okay, the stuff that I needed to fork it for is now merged in. So I want to go back to the main repository. Like it is almost impossible to get that submodule changed over. It's like this really weird system. There's a ton of other things in there that are just wonky. And the Zephyr manifest system completely does away with that. Like you can do anything you want. And that file is you totally available for you to read. You can understand when you commit a new manifest file what the commit message means. It's just kind of like a better system. Some of the advanced parts of the manifest system, the biggest one is inheritance. So the ability for you in a manifest file to say, go get this repository and check if that repository is any manifest files and then go get those. And you have this like huge web of recursion that works really well. But that can cause for huge checkouts. And so Zephyr's built in this idea of an allow list or a block list that says, yes, go through that entire recursion web, but only allow these certain packages or don't allow these packages that I don't need. I haven't used it personally, but there is this concept of grouping that I'll cover on at the end, which instead of saying individual packages you should allow or disallow, you can add packages to groups and then allow or disallow the entire groups. It's like a switch that turns off a bunch of stuff. And I just wanted to put in this call out that the ability to change the branch tag and commit in those is a great way for like during your development. But also, like I said, it locks those projects to a certain snapshot. So if you go back to it later on, you're going to be able to build it in order to tie all these together. Zephyr's meta tool, which is called West has manifest tools in it. It is what's responsible for going and finding that initial manifest file and following the recursion of them. And it includes some tools that you can use to kind of troubleshoot, like, why am I not getting the package that I thought I was a getter? Why am I getting all of these extra things? But as I'll get back to a whole bunch of times on this talk, I'd really like to talk more about the application side here. And applications, they are really great for manifest files because they can do the same thing that the Zephyr tree does. So the Zephyr tree is going to use the manifest file to figure out where all the Zephyr modules are. Your application should be no different. It should be like a mini version of the greatness that is Zephyr. And it might be a little too opinionated for you, and I'll apologize for that. But if you're not using the manifest files in your project, you're really not living up to the full potential of Zephyr. So please give it a try. All right, let's jump into the examples. So I think the first place that you would obviously go and look is the main manifest file for the Zephyr tree, which really isn't that interesting. This is what it looks like. It's 356 lines, but it's like 356 boring lines of manifest files, because it really just pulls in every repository that's in the project Zephyr organization, which is important that it does that. And it makes sure that if you're checked out to Zephyr version 3.3.0, you're getting the modules that are tested to that version. So that's great, but it doesn't go into some of the fascinating stuff. If you boil down that manifest file, it starts off just with the keyword manifest that lets the West tool know, yes, I'm in a Zephyr manifest file. In this case, it sets a default. And all that default is doing is basically saying, here is the URL that you should assume that all of my projects in this manifest file are using. And then it has a bajillion project entries. I just boiled it down to this one and kind of abstracted it. But the name set up here is a module name that gets added to that URL base for these remotes. So if you're looking at something you're like, I can't figure out where this project is coming from, that's because it's just taking the name of the project and adding it to that default base. And we'll look at that, I think on the next slide. Oh, I didn't cover the bottom part of this. So the important part is at the end, you have this self entry and that self entry is so it tells West, OK, the manifest file you're looking at right now, do these special things just for the code that's in this manifest. And here it sets that path, which is again going to get applied to the URL base. So it's going to go and get that repository. And this has a couple of special commands. It says grab this West commands file and import this extra directory of manifest. So don't worry if you don't understand this right now, we're going to go over the project level stuff like line for line, a couple of swim lanes for now. But I did want to look at I think the most confusing thing for a lot of people is where is the code coming from? And like I said in the previous slide, this doesn't have an actual location. Like you can't select something and put in your browser to get a clone of this. But if you were going to use a more explicit path, it would be very similar. I guess confusingly I changed the revision here. There's no reason that I should have changed the revision. The thing I'm pointing out is that one of them has the URL explicitly spelled out and the other one has it constructed from the actual way that manifest files are put together. But let's take a look at the more powerful parts of it, the inheritance and the allow list. Inherented specifically, we're now looking at a sample project that my company Goliath has up for you to look at. It's called Zephyr-training, I think. And this pulls in the Goliath library. Goliath is a module that's built on top of Zephyr. And Goliath is going to need other things to work. Mainly it's going to need Zephyr. And in this case, it's going to need Nordic's flavor of Zephyr, which is called the NRF Connect SDK. Some people call it NCS. But I'll probably call it the Nordic flavor of Zephyr from now on. And in this case, I use the import file called west.ncs.yaml. And if we look inside of that, you can see it has a project in it called NRF. That's the Nordic flavor of Zephyr. It's going to grab version 2.3.0. That's a tag from a Git repository, and it has the actual URL on it. In this case, it also has a line that says import true. And that's shorthand for go and look and see if there's a file specifically called west.yaml. And if it does, it's going to import everything in that. And that's going to be a lot of stuff. So for instance, I have never written firmware for Matter yet, but it's in there and it's going to get pulled in. Same with AMP, there's 50 different things that are going to get pulled in. And maybe that's fine. It can just sit there and not bother your project. It just takes a little extra time. Or maybe you want some control and you want to specifically say, I need these packages for my build. And that's what this green box on the left is doing. It's saying, okay, yes, grab all of these packages from the inheritance, but limit it using this allow list. The other thing is in this file that we are importing from the library, it has a self section and that self section includes an import command. And if we look at that manifest file, that just has one project in it. That is QC board, something Goliath uses for serialization for the SDK under the hood. And it's important to note that if that QC board wasn't in the allow list over on the original file, it wouldn't get pulled in. So you really need to pay attention to your allow lists. This is one of the places where using the West Meta tools to process your manifest file is going to help you figure out if something's not working later on. Now the thing that's actually going to do all the work for this, that West Meta tool is what you want to start off with. So when using Zephyr and using it in this way, you should kind of forget that Git clone exists and you should only use Git in it. Git in it's like maybe a superset of Git clone. It's going to do the cloning, but it's going to do it in a way that specifically puts the files in the right places. And if you do Git clone, you won't get that. And so when it starts out, it's just going to look for the manifest file that's in the repository that you give it. It's going to clone that top level repository into the place that that file tells you to put it. It's going to create a folder called .west, like a hidden folder in Linux, forward slash config. And that will be what it always looks for in the future when you run the next command, which is the West update command. So the West init command just sets up that top level repository, doesn't actually go through all the recursion. West update goes through all the recursion. And West update is a command you can run as many times as you want. It's good to run it compulsively. I think I have that on a slide a little bit later on. You should just get in that habit of muscle memory typing West update frequently. After that parses the manifest file, it's going to clone any repositories. Or if those repositories already exist, it's going to make sure that the head is set to the right hash on that. And then it's going to do the recursive thing and make sure it goes through all of the import chain. The command is usually pretty simple. So in this case, the dash M for West init just takes the actual location of the repository that you're starting from. And then the location where you want it to check out, I'm using the dot to indicate current directory, but you can put whatever location you want there. In some cases, like with the Goliath SDK, we support both the Nordic flavor of Zephyr and Vedela Zephyr. We don't have a West dot YAML file in our repository. We have a West dash Zephyr and a West dash NCS YAML. You have to choose between those. So you can use this command dash dash MF to tell it, look for a manifest file with this name in it. But otherwise it works the same as the basic init command. The other one that I use frequently is for changing the revision of the library that you're initially checking out. So if you think about doing some development on your project, before you merge it into main, you want to test and make sure that the initialization and the West update work. And you can do that by giving it the branch that you're working on. I would like to mention, you should not use branches in manifest files that you publish because the code in branch has changed. So what's in develop today is not what's gonna be in develop tomorrow. And that kind of breaks this whole concept of being able to lock. But when you're just testing something on a branch before it merges, then obviously that's fine. What you end up with is this file, the dot West forward slash config. And if you look in that, it's got very basic information. You can edit this manually if you want. If you break it, you're in charge of fixing it. But you can also just delete it and do the initialization again, which brings us to the first gotcha, which is if you run West in it, even if it fails, it will create that file. If you run West in it again, it's gonna throw an error. So if you get that error, that's why you're getting it. You need to remove that file and re-initialize. Always after the in it, you need to run an update and that update is just gonna go through and pull all those repositories. This screenshot is from a tree that was already set up so you don't see much other than West checking to make sure that the head is where it expects it to be. But you'll see a very familiar like get clone type of output if you're doing this for the first time. As I mentioned before, you wanna run West very, very often. And the biggest gotcha for this is like if we are doing development and someone's doing a PR review and you forget to run West update, you check out a new branch, the manifest file has changed now what's actually on your disk doesn't match the file until you run West update. I've heard of people putting West update as like a check out hook in Git. I haven't tried it, I would guess that it's possible. So if you've tried it, I'd love to hear about it and love to hear your experiences with it. All right, so let's actually talk about applications. So we wanna make sure that they're always able to build and like I think anytime I go into a new operating system, I'm wondering how do I actually take my application and put it under revision control? Like I feel like there should be better documentation around it. I guess this talk is part of the documentation but like what files do I need? What files do I not need? That's kind of what we're looking at with this talk. One of the things that you definitely should not do is fork Zephyr and make that like your application development repository because unless you're planning to commit stuff back to Zephyr there's really no reason to create a fork. I guess the worst version of this that I have actually seen people do is to commit the entire Zephyr tree to a repository. And the reason that's worse is that if you wanna update that there's no clear path for it. At least with a fork you could like re-sync with that fork but in generally it's not the right way to do it. I think very common that we see is for people to go into the Zephyr samples directory and add their own project folder and that project folder is their Git repository then. And like that technically will work like you'll be able to build the project but the project doesn't have any visibility to what version of Zephyr that it's like kind of inside of but not really is. And so if that Zephyr changes around it it has the potential to break your code. Similar and I guess the more promoted way is to have an out of tree directory like this one my sample project in my home directory and then you would call this helper script from like some centrally installed Zephyr workspace that sets up the environmental variables. And just like with the last slide this will definitely work like your application will build but your application doesn't know what version of Zephyr is centrally loaded. And if you're developing multiple applications if you pull up the Zephyr tree for one application the other application doesn't know it when you go back to that it's not gonna build and you don't know necessarily how to get back to the last snapshot that built well. And so really the right way to do this is to use a manifest file in your project because it's like where you write down all this important information and commit it. This is the directory structure that we've settled on. We use an app folder and that is actually where the code from your project is located. And then next to it dependencies or depths folder and that's where the tree and modules are located. Now these names are not like Zephyr specific we just minded on it. So name them anything you want but I think that this structure makes a lot of sense and so that's what we're gonna detail from here on out. Everything in this folder then is controlled by the manifest files but it's only the apps folder that is your code. None of the other code is actually committed to repositories that like forking Zephyr copying Zephyr doesn't happen it's just gonna get pulled in automatically by the manifest files. So it's gonna lock everything to a known version the way that you want it. It's only gonna track the files that you're writing which makes like reviews a lot easier like you're not looking at a bunch of files that are in there maybe you need them maybe you don't like the files in your repository or the files that you need. It does install its own copy of the tree. So the tree is in the project folder once it's installed in your drive and only that project uses that tree which is gonna get us to build environment. Maybe I should have put this on one of the cons but one of the things that you should keep in mind is there are a few other things that go into a build like the Zephyr SDK which is the collection of all the compilers those don't change a lot so generally install that once on your system. If you need to track it you could like put that in your changelog like what version you're building for but I haven't run into a lot of problems with that. The other one is Python can change a lot between systems and so at Goliath we advocate for and use virtual environments because then I know that something installed in my system isn't gonna cause a thing to build or not to build and it's really quick it's kind of out of the scope of this talk but it's really quick to set up one virtual environment when you're doing the install of your Zephyr application. The downsides of this are gonna be the disk space in our modern age of like terabyte multiple terabyte disks even solid state terabyte disks I don't think this is really an argument but if you're worried about space if you put a project kind of into cold storage you can just delete the depths folder and next time you need to use it a West update will pull it back so I don't think that's really anything to worry about. The other one I think is worth mentioning is that VS Code is kind of playing catch up on this like our partners at Nordic and at XP are both working on really great tools for working with Zephyr in VS Code but neither of them work well with this project manifest like how do you pull in the project manifest and tell it that Zephyr is in the depths folder like that's not quite there yet but they're aware of the problem and working on it and I think we'll see support for that soon. If you are interested in Zephyr tools in VS Code and like all of this works Glyceo and founder Jonathan Berry is doing a talk tomorrow on those tools and I'm sure he'll touch on this issue and before I leave this swim lane I would like to thank Ask Your Stavik Hustad who had looked at some of the stuff we're writing on our blog I know last year or the year before and said, hey, have you guys looked at using manifest files for projects and we had not and it really changed the direction of what we're doing and made things a lot better so that was awesome, go read his blog post and thank him on social media. Let's go through an example of setting up your applications and we're gonna start a new Zephyr application. We wanna start by creating the west.yaml file in an app directory. We wanna add an entry in that manifest file to pull Zephyr in. We wanna add the modules that Zephyr needs and we wanna limit those modules to just the packages that we want in our project using the allow list. So the beginning is very, very easy in fact it can be one line fewer than this. The version line is not actually necessary that tells west, hey, if you're not this version you should throw an error instead of continuing and this is to kind of gate it so that if you have directives in your manifest file that are not yet supported that you don't try to build without those because mayhem can happen. But really the important part for this first start is just setting up a self entry that sets up that apps folder and so this just says, hey, when you do west in it it's gonna look at the self directory and put things where we expect them. The next step is to actually get Zephyr into the project because we want our own dedicated version of the Zephyr tree in our application and so I've just added a project's entry here. It calls out the name Zephyr, a URL of where to find the code the actual revision. This is a tag from Zephyr under the revision right here a git tag and then the path. This is saying I want a depths folder and this particular package should go into Zephyr. I guess I was supposed to have that green arrow is what I was just talking about if you couldn't follow. If we try to build this though it's not gonna build and the reason is we don't have things like the hardware abstraction layer. So I tried to build this for like an NRF 52 and I got all these errors. So we need to go back and add some imports to Zephyr. So you can see I've added this import section right here that says go and get the west.yaml file and that is gonna pull in the entire universe of repositories. So we'll deal with that in a little while. There is a change from the previous that may not be obvious at first and that's I've taken out the actual path directive for Zephyr. So before I was saying put it in a depths forward Zephyr directory and that's because I've added this path prefix that says we're gonna put everything that we get from this import and from this into the depths folder and it will just automatically use the name of this repository for the sub folder for the repository itself. So you get a Zephyr with this repository in it and then for all the imports, you'll get like sibling folders to that Zephyr folder which is really what we want. And this is the point at which the version comes into play. We were at 0.7 before the path prefix didn't get implemented until 0.8. We're at like, I don't know 0.14 or something like that at this point but this is really just saying the minimum version that can be used. All right, so let's take care of the yuck part of this. We don't wanna pull in the entire universe. So in this version of the manifest file we've added a name allow list and NRF 52 840 is a ARM chip and so we need Seamsys library, we need the Nordic hardware abstraction layer and we need some of the Nordic libraries to build it. And when we do the West update for this it makes that a really nice process. So the three green lines are the three things that are our name allow list. You just pull those in, that's for simple build what you wanna do instead of spending like literally 20 minutes pulling in I don't know how many packages. And our final tree is gonna look like this. So the application folder is the mys of our application folder, you would make that but the actual code from the repository that we're tracking on GitHub is in the apps folder. You can see the .git file there. This is why you use West in it and not get cloned because get cloned would have put all those files into the mys effort application folder and it wouldn't have set up a path to that configuration file and it just doesn't start the process. So again, West in it, not get cloned. And then these folders, the .west folder and the depths folder, those are not actually in our repository, those get pulled in by the West tool after we use West in it to pull from our repository. So that's the very basics of an application. Certainly at that point, you're gonna wanna start putting other things. So not just an application that can build a legitimate arm for firmware, but actually something that does something. And the first thing is probably adding external libraries. So Goliath is a library built on top of Zephyr. So I'm gonna use Goliath as the example here, but any library that you wanna add to your project should work in the same way. In this case, I have added a second project entry here below the Zephyr entry that is for Goliath. The thing that kind of gives me heartburn about this step now is we limited Zephyr to a certain number of modules. And so the question is, are those modules everything that needed for this library? And in general, this lower block of Goliath actually got from the library, read me, will often tell you, just put this in your manifest file. And this one has its own import. So it has a manifest file specifically for being included as like an external library that pulls in, and I think I showed it on a slide before the QCBOR library. So that's nice that that takes care of, that inheritance kind of takes care of like the things that you need. You just need to make sure that those are on the allow list. In this case, QCBOR is not on my allow list. And so this isn't gonna work very well. So you do have to look at the manifest files, did you add them and make sure that you're not gonna have problems. The other thing that I worry about is matching versions. So if I have this tag of Zephyr 3.3.0 and I have this hash of Goliath, is Goliath tested to work with that version of Zephyr, just kind of like making these versions match to the whole point of these manifest files. In this case, I manually match them so that I know that they're work. But in general, we know this one at least has a manifest file. You should go and look at the manifest files for your library and see what they say. So let's actually step into that. Let's go into the Zephyr manifest file for sorry, the Goliath manifest file for Zephyr. And the first thing we see in Goliath manifest file is it includes an entry for Zephyr, which is really nice because since there's a revision here, we assume that that library maker is saying that this version of Zephyr is tested and known to work with this library. And for us, since we just had those two entries, the Zephyr and the Goliath library, we can actually use the inheritance to make sure that we're always locked to that. So instead of always having to make sure we're matching, we can just take our original file right here and we can change it up. So under this, we have two projects entries, one for Zephyr and one for Goliath. But we can actually move that to just be one project entry and kind of glom everything under. So we take the Goliath section that our external library and move that up and then we add Zephyr to the name allow list because we looked at the library and we saw that it was already going to pull in Zephyr if we imported that list. And so we have a little bit cleaner manifest file and we have one that we know as we update our external library, it's always going to be locked to a known working version of Zephyr. This can be tough if you have big builds because you can't just be like every time I add a library, I'm gonna use that library file. Like obviously there's some push and pull, but it still is a pretty good system. And once you commit it, know that it's working the first time, it generally is pretty stable. Do put some testing in as you go for upgrades though so you can make sure that you don't destabilize your system by upgrading one external library not checking its dependencies. In addition to external libraries, I think you are gonna wanna add your company's own helper files. And so Goliath definitely does this. Here we can see changes to the apps directory. So we're not just putting stuff in the depths directory, we're putting custom things into our app directory like these are boards that Goliath is designed that are not in the Zephyr tree but need their own board definitions. We use them in several different Zephyr applications and so we store them as a central repository and then we pull them into each project that we need. There's also a helper library in here that gets installed in the source folder that we pull in in the same way. So it makes reusable code really easy and the other thing is, I know I keep harping on the same thing but locking to a revision is really convenient. So for instance, if our helper library has a breaking change, older builds are still gonna build because they're locked to a specific snapshot of that older library. So until you manually upgrade what version of the library you're using in your application, you're not gonna have problems with the build, you're just not gonna have the newer features. So it makes that really easy to follow along. So I know that's a ton of stuff and I know I'm going fast but I do have limited time and a lot of geekery to get up to here but most things are pretty simple, especially starting off. So you're not gonna have to jump into like the most complicated manifest files the first time you add them. If you get stuck, go and look at other examples. I would also encourage you to go and the first thing you should do is go and look at the docs. There's a lot of docs on manifest files. If you need to do it, you probably can. There's not many blockers here and you can probably do it in a couple of different ways. If you do get stuck, go to the Zephyr Discord channel. The thing about it is the people writing Zephyr wanna know that it's gonna use. So they're gonna be happy to talk to you about it and there's a good chance that they're gonna be able to fix your problem quickly or at least tell you that it's a known problem and not solvable. So lots of help there. There are some other features that you should definitely know about but I'm not gonna dig in too deeply here. I talked about a little bit about validating manifest files and this is pretty important, especially if you have problems with manifest files, you're gonna scratch your head because you're like, what's going on with that? And so you might wanna look to the resolve command. This is, or I guess it's a flag, west manifest dash dash resolve. And what this does is says, go through the entire web of manifest files and give me one manifest file that combines them all and then you can look at it. Now I ran it just on that sample program that I was building up for this and I was surprised, I did not expect to see this group filter at the top. I have no idea what this stuff is. I certainly didn't write it in my code. I shouldn't say I have no idea. I do know that this is disallowing certain groups and I know I don't need those groups. So that's fine. But in this case, if you're not seeing some code in your tree that you were expecting to see, the resolve command is gonna show that it's not there and it should show why it's not there. The other thing that's really good, especially when you're making a release is to use the west manifest dash dash freeze command. And this does something very similar to the resolve command. It goes through the inheritance and makes a single file for it, but it's gonna change all of your revisions to actual commit hashes. So it's gonna take branches and tags and turn them into hashes. And I really do think this is a best practice for releases for sure. It just kind of saves you that error of like, oh, I committed main as a revision or something that's gonna change over time. If you do the freeze and then go through manually and look at what you're doing, seeing the differences, you might decide it's best for me to commit these as hashes. Like I said, especially when you do a release because that's just from time to time. But I mean, also when you're doing a PR merge, you might decide our best practice is to always use a hash and not to use a tag. There is, I guess, a convention that tags never change, but it is possible to move tags. And if that happens, it could break your build and maybe you don't wanna open yourself up for that kind of thing. I mentioned that I would cover groups. I've never used them myself, but it's easy to find them. They're in the main Zephyr manifest file. And here's a good example of why you would use groups. So there's this babble sim. I'm not an expert on this, but I think it's for simulating during twister runs or something like that. And there's a bunch of packages in there that use it, like maybe six or 10 packages. And you could put those six or 10 packages on a block list in your manifest, but that's kind of a pain. And so instead you add all those to one group and then you have a one-liner that disallows the group. So the group filter at the top says anything that's in this group, don't include it in the West update. We're really getting kind of out on a limb on things that you would actually use here, but we used it in our SDK and I thought it was cool. And so I thought I'd add it here. Marcin Neostra, who is a firmware engineer at Goliath and really has done the line share of work on our SDK and also is a contributor to the network stack of Zephyr. He set this one up because there were some patches that needed to happen for the Nordic flavor of Zephyr. I don't even know what those patches are for if we're using them anymore. But the way that they're set up is by using a West command. So he added West patch as an extension command in our SDK and it's this directive, the West-commands that pulls that in. So if you're using any kind of a library that uses those commands, they will get pulled in as long as that's in their manifest file. In conjunction with this, there's another interesting piece of the manifest system called user data. Now, West doesn't care what the data is. It just makes it available in a way that's accessible. And so in this case, on the bottom right, we have a manifest file that sets up user data that is saying, okay, here is the directory where the patches are located. And in the upper right, the patch.py, which is what gets called by that custom West command is looking up the directory location for that. So if we have vanilla Zephyr and Nordic Zephyr and we have different patches for that, you can use user data in different manifests to select which patch is getting built in. So like I said, there's probably a way to do just about anything you're looking to do. You just have to go down the rabbit hole of like what all this stuff is about. I think that's enough oddball ones for now. So let's go on to the summary. So I think when you think about revision control in Zephyr, you should definitely think about manifest files. Certainly the Zephyr project does. And so why shouldn't we as application developers, it's gonna stabilize your build environment with those few caveats of like the Zephyr SDK compilers and such. And certainly it's gonna be useful to you in making reusable code very easily available. So you just put a repository somewhere that you can use multiple projects and call that in in the manifest for each project. And I think those reasons alone are more than enough to get up, get started. And I think you'll be happy that you did. If you wanna dig deeper into this, like I said, the Zephyr docs are the place to go. So I have a link up here for that. If you wanna look at manifest files as examples, a couple places to start that I used in this talk, there's a good application manifest file in our Zephyr training repository. And then kind of library module size files. You wanna look in our Zephyr SDK. There are three different manifests in there. So you can see different approaches that way. And finally, if you are interested in a device management solution for microcontroller level IoT devices, Goliath has a free tier for up to 50 devices. We'd love to talk to you and have you play around at the platform and see if you like it. That's it, thank you so much for having me today.