A Yocto power user’s guide to tooling: Part III
A better Dev Container setup + Agentic tools
A Yocto power user’s guide to tooling: Part III
A better Dev Container setup + Agentic tools

Third time’s a charm right?
Welcome to my third attempt at documenting my ideal Yocto development environment. I‘ve picked up more tips and tricks since my last update and I’ve excited to share them here. Hopefully you can incorporate some of these pointers in your day job or hobby projects for some efficiency wins.
I will be covering the following topics in detail:
- How to setup VS Code for Yocto development using Dev Containers and the BitBake extension
- How to setup the oelint-adv linter and integrate it with VS Code
- How to integrate agentic tools to the same setup and use them with confidence. I’ll be using Claude Code here as an example.
All code snippets mentioned here are from my working reference repo at https://github.com/ruvi-d/simplest-yocto-setup
Prerequisites
Beefy hardware: Do yourself a favor and get your hands on the fastest PC with the most CPU cores and RAM that you can extort out of your employer. A desktop with 16 cores and 64GB of RAM is my recommendation. Note that even with the prevailing RAMpocalypse, 32GB is the new minimum for RAM in 2026 as published in the Yocto Wrynose release announcement. For pure build speed, the number of cores is the most important factor as shown in the graph below from PART I.

Yocto Scarthgap core-image-minimal image build time vs number of CPU cores
Obviously you’d want to benchmark with your own code base to find a sweat spot.
Native Linux or WSL2: While native Linux is preferred for obvious reasons, WSL2 is still viable if your employer gives you no other option. If you are stuck with Windows, remember that you can override the default maximum RAM limit. The default is half of the system’s RAM. e.g. on my 32GB work laptop, I’ve adjusted the limit to allow a maximum of 24GB to WSL2. Also remember that you will have to periodically and manually “optimize storage” to recover free disk space.
Docker: I would NOT recommend setting up your host OS for native Yocto development. i.e. don’t follow the official Yocto quick start guide. It is for someone looking to get their hands dirty with Yocto for the first time. It is not ideal for long term, collaborative development with a team. Developing inside a Docker image is the idiomatic way IMHO for the following non-exhaustive list of reasons:
- Reliability: Since you don’t have to install system packages or even VS code extensions to the host OS, you are less likely to inadvertently screw up your system trying to install and configure random packages. It can seem hard to imaging working without running “apt install”, but if you haven’t heard already, this is the whole shtic with immutable Linux distros. They are gaining popularity with the professional Linux user populous that just want a stable OS to get work done. I too am a immutable distro convert. I’ve been dailying Bazzite and Bluefin for about 2 years now after a random update borked my Fedora install. I digress.
- Easy setup: You don’t need spend time setting up a new build machine or help a colleague setup theirs. Not to mention that it is idiot proof; especially for team members that are new to Linux.
- Consistency: Your dev team and your CI builds can share the same Docker image. Making it easier to reproduce issues and avoid issues in manual setup altogether. As a bonus, everyone can also share the same Yocto share state cache (SSTATE cache) to speed up builds.
- Run newer/unsupported distros: This is a life saver if you have new laptop hardware that requires the latest and greatest kernel and/or if you need to work with older Yocto releases.
I acknowledge that the Docker approach demands additional effort upfront to sort out a lot of the tooling and that some things like running QEMU with a GUI is a lot harder to do. But the pros far out way these inconveniences.
Onwards!
1. VS Code + Dev Container setup
First, I want to make a quick case for the use of IDEs in general. IDEs are a productivity multiplier! The tooling provided by a good IDE can abstract complexities and make it easier to navigate and debug a large code base. If you have team members that insist on doing everything in the command line using Vim or Emacs; all the power to them; you do you! For everyone else, IMHO you should standardized around a modern IDE based dev setup. This makes it easier to onboard developers and provides a sane/stable default that will work for most people.
In terms of the choice of a IDE, it is a no brainier for Yocto development. VS Code with it’s, dare I say, great BitBake extension is the way to go. The cherry on top is it’s Dev Container feature that lets you develop inside a Docker container transparently.
1.1 Dev Container setup
The said Dev Containers feature makes developing using a Docker Container very n00b friendly. Here is a link to a pull request where I’ve added Dev Container support to Bootlin’s excellent simple-yocto-setup example project: https://github.com/ruvi-d/simplest-yocto-setup/pull/3
There is a lot there and I will walkthrough the important bits, but before we dive deep, let me give the TL;DR up front:
- Use the more advance “Docker Compose” option to setup your Dev Container in order to unlock a bunch of customization options
- Use a Dev Container specific Docker image to extend your CI build container with developer specific configs and tools
Now onwards to the detailed walkthrough:
**devcontainer.json: **This is the main file that tells VS Code what Docker image to start and how to start and configure it. If your VS Code working directory has a devcontainer.json file in .devcontainer folder, VS Code will automatically prompt you to open the project in a container.

If you miss that pop-up, check the notifications bell for the notification on the bottom right or open the command palette (F1 or Ctrl + Shift + P) and find the “Dev Containers: Reopen in container” command as shown below.

Now let’s break down some of the more important bits in that Dev Container yaml file
"name": "CROPS 22.04",
This name is arbitrary and it’s only significance is that it is what is shown on the bottom left when you open the IDE in the Dev Container

"dockerComposeFile": "compose.yaml",
"service": "yocto-dev",
"workspaceFolder": "/workspaces/simplest-yocto-setup",
These lines specify how to start the Docker image. I recommend using Docker Compose file here in order to unlock the most configuration options.
compose.yaml: Now let’s look at the said compose file in detail
services:
yocto-dev:
build:
dockerfile: Dockerfile
command: sleep infinity
...
volumes:
# Mount working dir
- ../..:/workspaces/simplest-yocto-setup
# Mount shared caches dir
- ${HOME}/yocto-caches:/workspaces/caches
# Mount SSH credentials for git access
- ${HOME}/.ssh:/home/yoctouser/.ssh:ro
# Mount shell history files
- ${HOME}/.zsh_history:/home/yoctouser/.zsh_history
- ${HOME}/.bash_history:/home/yoctouser/.bash_history
...
The volumes here is used to mount the source code and a bunch of other host system files inside the Dev Container. The “yocto-caches” folder here is very important. This is where I have defined a dedicated location outside of the source tree to store the download and shared state cache. This way I won’t loose my caches when the Dev Container is rebuilt or my build folder is deleted. Remember that you will need to pass through your git credentials. I’ve simply mounted my host ~/.ssh folder as read-only to achieve the same. If this bothers you, the official documentation list other options. The last two lines where I pass through the shell history is optional, but I like to have my history persist beyond the ephemeral Dev Container instances.
Now it’s worth noting the “yoctouser” references here. This happens to be the default user with the UID 1000 in the CROPS image I have selected as the base of my Dev Container. UID 1000 is the default user on most distros, so “yoctouser” should nicely map to your host machine’s user. i.e. you shouldn’t have any issues accessing the files created from the Dev Container. If there is a user ID conflict, you will have to update the Dockerfile and the compose file to create the UID you want and start with with it. There are some tips here.
Dockerfile: This is gives you a chance to extend the base image with tools or configurations required for developers.
FROM crops/yocto:ubuntu-22.04-base
# Switch to root to install packages
USER root
# Install pipx required for kas install
# also installed zsh to aid local development
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
pipx \
zsh && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Switch back to yoctouser
USER yoctouser
# Install kas and oelint(BitBake linter)
RUN pipx ensurepath && \
pipx install kas && \
pipx install oelint-adv
# Add pipx install dirto PATH
ENV PATH=/home/yoctouser/.local/bin:$PATH
In my example project, I have taken an official CROPS build image as my base and added kas, oelint-adv and the ZSH shell. This is also where you can resolve UID issues as mentioned in the previous section. My general recommendation is to keep the base image as minimal as possible, including only the minimal tools required for CI builds. Avoid adding developer only tools to the base image. They can be added via the Dev Container Docker file as shown here. e.g. include kas but not ZSH to your base image.
Another way to add developer only tools to the Dev Container is via the Dev Container Features. There are a large collection of community features that let you pull in functionality as a Docker image layer. For example, I’ve used a ZSH feature as shown below to install ZSH to my Dev Container and also to enable the “git” and “zsh-autosuggestions” ZSH plugins in the zshrc.
// Add ZSH support
"features": {
"ghcr.io/nils-geistmann/devcontainers-features/zsh:0": {
"plugins": "git zsh-autosuggestions"
}
},
"postCreateCommand": "git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions",
Shoutout to the awesome zsh-autosuggestions plugin ❤.
The astute amongst you may have realized that this means that the “apt install zsh” I had in the Dockerfile is redundant. Yes, that is correct. The Dev Container feature would have installed ZSH, even if I hadn’t installed ZSH via the Dockerfile.
**devcontainer.json -> customizations: **The largest section in the devcontainer.json file is the customization block which lets you change various default VS Code settings, including extension specific settings. Most of the configurations should be self-explanatory. Only thing worth mentioning at this point is the list of extensions that I have chosen to install. Don’t go overboard with extensions; less is more. Some extensions can be buggy as hell and make the IDE unresponsive. The following is my minimal recommended list for Yocto development.
"vscode": {
"extensions": [
"yocto-project.yocto-bitbake",
"streetsidesoftware.code-spell-checker",
"mads-hartmann.bash-ide-vscode",
"ms-python.vscode-pylance",
"ms-python.python",
"ms-python.debugpy",
"ms-vscode.makefile-tools",
"ms-vscode.cpptools-extension-pack",
"wickscc.openembedded-kickstart",
"plorefice.devicetree"
],
1.2 BitBake VS Code extensions
This is the special sauce that elevates VS Code from being yet another text editor for Yocto to a powerful IDE! I can’t stress enough that you should take the time to read the documentation at https://marketplace.visualstudio.com/items?itemName=yocto-project.yocto-bitbake to get a baring of what is possible. There is a lot it can do. Some of my personal favorites include:
- CTRL + click to go to definition
- Support for “multi configurations / build folders”
- Devtool integration
I won’t rehash the details that are already in the extension’s home page. If you are looking for a summary, I have a section in PART I.
1.3 Using Dev Container lifecycle scripts
Dev Containers lets you inject scripts to run at various stages of spinning up the development environment. These commands can run on either the host machine or inside the Dev Container Docker container itself.
For example, I have added
"initializeCommand": {
"createCacheDir": "mkdir -p ~/yocto-caches"
},
which runs on the host machine very early in the process to create the shared download and shared state cache folder that my Docker Compose file expects to be present on the host PC.
Then there is
"postCreateCommand": "git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions",
that runs after the Dev Container Docker image is built to my favorite ZSH plugin to the image.
Finally we have
"postAttachCommand": "test -d build || bash .devcontainer/dev/setup-builds.sh",
which runs after the Dev Container boots up to automatically checkout the layers and setup the build directories using kas. The “test -d build || ” part is used to skip the kas checkout if it was already run once. Otherwise you’d loose any custom modifications done to the local.conf.
Use these command hooks to eliminate any manual setup steps that would otherwise been required to be done by anyone onboarding to your codebase.
2. oelint-adv linter setup
VS Code’s BitBake extension is great, but it is not sufficient. On the linting/static analysis front, it is capable of catching obvious syntax errors that would result in BitBake build or phrasing errors. But it lacks the style and best practice enforcement that a tool like Clang-Tidy would bring to C++ development or like what hadolint does for Dockerfiles. This is where oelint-adv comes in. It can be very naggy at times, but that is worth it for two primary reasons.
- It catches subtle bugs
- It enforces formatting and styling guides
A classic example for #1 is when I accidentally type A:foo:append instead of A:append:foo. This tool is able catch that as a common mistake. This can be a big time saver, avoiding having to troubleshoot subtle bugs. It also helps you learn and instill the many idiosyncrasies with BitBake.
Regarding #2, it is great at things like auto formatting recipe files and at fixing extra white spaces. It also enforces recipe variable ordering so that variables like SUMMARY, SRC_URI, LICENSE, etc are in the correct order as per the BitBake style guide.
2.1 Setting up the oelint-adv VS Code extension
As with any linter or static analyzer, it is of little use if it doesn’t “automatically” work and provide suggestions/warnings as part of the developer workflow. Developers are a lazy bunch. As such, if you ask developers to manually run the tools, the chances are that they never will do it. That is why IMHO, the oelint-adv extension is a must. When configured, it will run on every file save and give the all important red/yellow squiggly lines directly in the VS Code editor pane.

oelint-adv errors showing up as squiggly lines in the editor
To get the oelint-adv extension working inside our Dev Container, we need to do the following:
- Install the oelint-adv cli tool via pypi to the Dev Container Docker image: src link
- Create a configure for oelint-adv to do things like suppress warnings that you don’t care about: src link
- Set the
OELINT_CONFIGenvironmental variable to the path of the said configuration file so that the oelint-adv cli tool can find it: src link - Install the oelint-adv extension to the Dev Container: src link
- Tweak extension settings. Here I have allowed the extension to run the formatter and update my files: src link
That’s it!
2.2 Running oelint-adv as part of CI
In addition to running oelint-adv in VS Code, you would also want to run oelint-adv in CI as a merge gate for pull requests. There you can enforce policies like a zero tolerance for oelint-adv warnings/errors in modified files. This is akin to treating warnings as errors in the C++ world. This forces developers to fix the linter warnings without having to burden human reviewers from having to catch them.
In my fork of simple-yocto-setup, I have setup a Github workflow to run oelint-adv and then to also do a bunch of test builds for the various machines targets.

my example CI job for pull requests: link
You may notice that I have set it up so that Yocto build stages only run if the oelint-adv stage passes. For bonus points, I have also added a stage to run a set of testimage tests on QEMU. The logic to invoke oelint-adv is here and is pretty simple.
If you are wondering where those Yocto builds ran, I had setup a self hosted actions runner on a beefy PC to do the builds for this toy project. For production repos/jobs you’d obviously want to setup some cloud infrastructure so that you can scale up. Just make sure you also setup a shared cloud SSTATE cache or else the builds will take forever and your cloud bills will skyrocket.

Remember that oelint-adv is very paranoid and will through false positives all the time. When this happens, add # nooelint: <name.of.rule.to.ignore> lines to your recipes to suppress them.

Suppress false positive with "# nooelint"
3. Claude Code setup
Just like how I described IDEs as a productivity multiplier earlier in this blog, agentic coding agents are for sure the next level up. But how do you leverage this power effectively?
Opinions on what a modern development setup looks like with agentic tools are divided. There are some tool providers that proclaim the end of IDEs altogether, going all-in on CLI tool based workflow. They think that a interface that lets you “herd” multiple agentic coding agents is what the future of software development will look like. In the future they foresee, agentic tools will be so good at code generating that there is no real need for a legacy text editor interface of ye olde.
That could be the future, but today in May of 2026, you still need a IDE to be productive with Yocto development. This is because we embedded platform engineers don’t spend most of our time writing code. Instead, most of our time is spent reading code, tweaking configurations and debugging. All of which is greatly aided by a full fledged IDE. Therefore, I’d like to make the case that what we need today is a IDE + coding agent solution.
With that said, let me describe what has worked for me so far.
3.1 How to get agentic tools to work with Dev Containers
For agentic tools to be effective, you need to give it access to the code and build tools. For us this will means giving access to run BitBake commands. Since our dev tools are sandboxed inside a Docker container, we need a way to get the agentic tools to run inside this sandbox.
The best way to do is to simply install a VS Code extension. For Claude Code, you’d want to install the official extension. The Dev Container will be transparent to Claude Code and it will run sandboxed inside the container.

Leveraging Claude Code in simplest-yocto-setup repo
If your favorite agentic tool doesn’t have a VS Code extension and only comes as a CLI tool, you will need to install the said tool into the Dev Container Docker image. As described earlier in the blog, you have two options to do this. Either use a Dev Container feature (e.g. for Claude Code) or add the install command to the Dev Container’s Dockerfile (e.g. add curl -fsSL [https://claude.ai/install.sh](https://claude.ai/install.sh) | bash to the Dockerfile). Then you can launch the CLI tool from VS Code’s integrated terminal.
In general, this is a subpar solution riddle with bugs and rendering issues. I’ve seen issues like copy/pasting inconsistencies and broken file hyperlinks. This is typically because of broken dependencies due to the stripped down nature of a typical build container. They tend not to include packages a typical desktop distro would have that some agentic tools assume will always exist. Depending on your coding agent of choice, your mileage will vary.
Therefore given a choice, use the VS Code extension. It will be your most stable and least buggy option. For reference, see this pull request that enables Claude Code in my simplest-yocto-setup fork: https://github.com/ruvi-d/simplest-yocto-setup/pull/4
3.2 Pro tips
1. Pass through tool metadata from host to the Dev Container
For the best user experience, you will need to mount your agent’s metadata folder into the Dev Container. The metadata usually include login cookies and the chat history. For Claude Code, mount your ~/.claude folder as done here. Other tools may require you to pass through login API keys via environmental variables.
2. AGENTS.md / CLAUDE.md file
To get the most out of your agentic coding tools, you will want it to be able to build, run unit tests, run linters, etc so that it can find issues in generated code and fix it itself. Those instructions should go to your repo’s AGENTS.md or CLAUDE.md file. Don’t go overboard with the directives, less is more.
3. Automated testing in CI
Running automated tests as part of CI is an obvious best practice that is now even more important with agentic tools. The benefit of automated CI tests are two fold. One obvious benefit is to catch unintended feature and build regressions. The other less obvious benefit is that it is cheaper to execute large test suits in CI as opposed to having your agent burn tokens to run them locally. You can even close the loop between CI builds and agents running locally by using a MCP server to connect an agent to Github or similar service. Then your agent can code gen, run basic tests locally, push changes to a PR, check for errors in CI, fix errors, push and repeat. It’s pretty crazy when it all comes together.
Regarding the testing scope, for large production repos with many machines and images recipes, you’d want to build all possible combinations at the minimum. This is where having a single mono repo helps. It gets unnecessarily complicated then you have discrete repos for layers.
In addition to simply building targets, you should also run tests using something like the testimage feature supposed natively in Yocto. I’ve also seen projects using the robot testing framework as an alternative. Tests can run on QEMU as I described in the oelint-adv section or you can have them run on actual hardware; i.e. hardware-in-the-loop style testing. There are a few Yocto summit talks on Youtube that dive into the details if you are looking for more info.
3.3 Alternative option — the Warp terminal
Finally let me add a small plug to the Warp terminal as an alternative to the VS Code setup I’ve been describing. If the BitBake plugin for VS Code was not a thing, this is probably what I’d use. I like how it integrates IDE like rich text editing features with a cool terminal.
It’s killer features include it ability to “attach” an agent to an interactive shell. As in, it can take control of a SSH session or a GDB shell. Pretty neat stuff! It can also do something called “warpify subshells”. This can be used to solve the problem we discussed previously about how to get agentic tools inside of a Docker based development environment.
I’d encourage everyone to take the Warp terminal for a whirl!
that’s all folks!
메타데이터
- post_id
- b45ca5c75c20
- slug
- a-yocto-power-users-guide-to-tooling-part-iii-b45ca5c75c20
- url
- https://medium.com/@ruvi-d/a-yocto-power-users-guide-to-tooling-part-iii-b45ca5c75c20
- canonical_url
- https://medium.com/@ruvi-d/a-yocto-power-users-guide-to-tooling-part-iii-b45ca5c75c20
- author_url
- https://medium.com/@ruvi-d
- status
- ok
- fetched_at
- 2026-07-10 13:32:34