Devtools
Curated install recipes for the tools a workstation needs: what each one installs, its versions, and its configuration.
Devtools are development tools that do not come with the base OS: language toolchains, Docker, kubectl, the Claude Code CLI, a browser IDE. Most take more than a package install to be ready to use: an upstream repository and its signing key, the right binary for the architecture, a service to enable, or a shell snippet to wire in.
A devtool is a recipe that handles all of that. You declare the tool’s name (and optionally a version) on a Workstation or a WorkstationConfig, and every machine the declaration reaches installs it the same way, every time it is set up. Declared tools survive a rebuild and repeat across a team, which is the point of declaring them instead of installing by hand.
We continuously add more devtools to the curated list, but there are also two ways to install software that is not included yet:
- Use
packagesto install a tool that ships as an operating-system or npm package (you can add an external repository if needed), or - Add a provisioning
scriptthat installs the tool during the workstation’s setup.
Both are ordinary configuration fields, so they are versioned with the manifest and applied to any machine that uses the config.
devtools:
- name: docker
- name: nodejs
version: "24"
- name: playwright
config:
browsers: [chromium, firefox]Each entry accepts exactly these keys. An unknown key (a misspelling, for example) is refused at apply:
| Field | Type | Description |
|---|---|---|
name | string | The recipe name. Must be one of the recipes below; an unknown name fails setup. |
version | string | Optional version. What it means is recipe-specific (see each page); omit it for the recipe’s default. |
config | object | Optional opaque blob, interpreted only by a config-aware recipe: kind, playwright, vscode-web and spire-agent. |
fatal | bool | Does a failure block the workstation reaching Configured? Default true, except in a personal layer. |
retries | int | Extra attempts within one configuration pass after a failure (0-5). |
The recipes
Languages and toolchains
- go: the Go toolchain, pinned from upstream or from the distribution.
- golangci-lint: the Go linter, installed with the Go toolchain.
- nodejs: Node.js and npm, from the upstream repository.
- python: the distribution’s Python 3, with pip and venv.
Containers and Kubernetes
- docker: engine, CLI, Compose v2, and buildx.
- devcontainer-cli: the reference devcontainer CLI; implied by a devcontainer declaration.
- kind: the
kindbinary, and optionally a whole cluster with ingress and a load balancer. - kubectl: the Kubernetes CLI.
- helm: Helm 4.
- kubectx: fast context switching.
- kubens: fast namespace switching.
AI coding tools and editors
- claude-code: the Claude Code CLI.
- codex: the Codex CLI.
- cursor-agent: the Cursor CLI agent.
- agy: the Antigravity CLI.
- vscode-web: the code-server browser IDE, started for you.
Cloud CLIs
Version control
Testing and shell
- playwright: the Playwright CLI plus browser engines and their OS dependencies.
- fzf: the fuzzy finder, wired into login shells.
Host integration
- passthrough-www-browser: relay URLs opened inside the workstation to your laptop’s browser.
Identity
- spire-agent: join the workstation to your own SPIFFE trust domain, so its workloads get SVIDs.
How devtools behave
They install in declared order. A recipe that depends on another tool ensures it
itself (claude-code will install Node.js if it is missing), but declaring the
dependency first makes the order explicit and lets you pin its version.
They are deduplicated by name across layers, last-wins on the whole entry. If a
workstation and two configs all declare nodejs, one nodejs install happens, using
the entry from the highest-priority layer, including its version and config.
Position in the merged list follows where the name was first seen.
They install after packages and before files, sources, scripts, and services. So a
provisioning script can assume docker compose or go build works the very first
time the workstation sets itself up.
They are gated on the workstation’s real state. Before running a recipe the
agent checks whether the tool is actually present (for docker, that includes
docker compose and docker buildx; for a configured kind, that the cluster still
exists). A tool removed out-of-band is reinstalled the next time the workstation applies
its configuration, and an already-installed tool is skipped.
Changing version or config re-runs the recipe. The entry’s identity folds its
version and its config blob, so editing either makes the next setup run apply it.
An unknown name fails setup. The workstation reports the failing step and stays
Configured: False.
Devtools versus tool configuration
A devtool installs software. A
toolconfig configures software that is
already installed: it writes the tool’s dotfiles on every setup run and installs
nothing. Several names appear in both channels (claude-code, codex, vscode-web,
git, gh) and are meant to be used together:
devtools:
- name: git # install git
toolconfigs:
- name: git # give it an identity
config:
userName: Ada Lovelace
userEmail: ada@example.comDistribution support
Every recipe supports Debian and Ubuntu. Most also work on Alpine, using apk
packages. Six do not: gcloud, aws, az, vscode-web, cursor-agent and agy. On Alpine,
each of these fails with a message that says why. Each page states its support.
Downloads always resolve the workstation’s architecture (amd64 or arm64) at install
time, so the same manifest works on an x86 cloud VM and an Apple-Silicon local VM.
- goThe Go toolchain: an exact upstream release, or the distribution package.
- golangci-lintThe golangci-lint Go linter, built with the workstation's Go toolchain onto the system PATH.
- nodejsNode.js and npm, installed from the upstream apt repository on Debian and Ubuntu.
- pythonThe distribution's own Python 3, together with pip and the venv module.
- dockerThe Docker engine, CLI, Compose v2, and buildx, with the login user in the docker group.
- devcontainer-cliThe reference devcontainer CLI (@devcontainers/cli), installed globally with npm.
- kindA local Kubernetes cluster on the workstation, with an ingress controller and a load balancer, reachable from your laptop.
- kubectlThe Kubernetes CLI, installed as a static binary for the workstation's architecture.
- helmHelm 4, installed from the official installer script.
- kubectxFast switching between Kubernetes contexts.
- kubensFast switching between Kubernetes namespaces.
- claude-codeThe Claude Code CLI, installed globally with npm and configured to bypass permission prompts by default.
- codexThe Codex CLI, installed globally with npm.
- cursor-agentThe Cursor CLI agent, installed from a specific Cursor release.
- agyThe Antigravity CLI (agy), Google's coding agent for the terminal, installed from a specific release.
- vscode-webVS Code in your browser, running on the workstation: code-server installed, started for you, reachable only from your laptop.
- gcloudThe Google Cloud CLI, from Google's official apt repository.
- awsThe AWS CLI v2, from Amazon's official self-contained bundle.
- azThe Azure CLI, from Microsoft's official apt repository.
- gitgit itself, the install companion to the git tool configuration.
- ghThe GitHub CLI, the install companion to the gh tool configuration.
- playwrightPlaywright with its browsers and their system libraries, ready for a project's browser tests.
- fzfThe fzf fuzzy finder, with key bindings and completion wired into login shells.
- passthrough-www-browserRelay URLs opened inside the workstation to your laptop's real browser, for OAuth and device-code logins.
- spire-agentJoin a cloud workstation to your own SPIFFE trust domain, so software on it gets SVIDs from the Workload API.