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 packages to install a tool that ships as an operating-system or npm package (you can add an external repository if needed), or
  • Add a provisioning script that 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:

FieldTypeDescription
namestringThe recipe name. Must be one of the recipes below; an unknown name fails setup.
versionstringOptional version. What it means is recipe-specific (see each page); omit it for the recipe’s default.
configobjectOptional opaque blob, interpreted only by a config-aware recipe: kind, playwright, vscode-web and spire-agent.
fatalboolDoes a failure block the workstation reaching Configured? Default true, except in a personal layer.
retriesintExtra 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

AI coding tools and editors

Cloud CLIs

  • gcloud: the Google Cloud CLI.
  • aws: the AWS CLI v2.
  • az: the Azure CLI.

Version control

  • git: git itself.
  • gh: the GitHub CLI.

Testing and shell

  • playwright: the Playwright CLI plus browser engines and their OS dependencies.
  • fzf: the fuzzy finder, wired into login shells.

Host integration

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.com

Distribution 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.