Imported from devcontainers/templates (
AGENTS.md). Install upstream withnpx skills add devcontainers/templates. Copyright stays with the author.
AGENTS.md
Guidance for AI coding agents (including the GitHub Copilot coding agent) working in this repository.
Repository overview
This repo contains the official Dev Container Templates.
Each template lives in src/<template-id>/ and is mirrored by tests in test/<template-id>/.
A template is made of:
src/<id>/devcontainer-template.json— template metadata and user-selectableoptions.src/<id>/.devcontainer/— thedevcontainer.json(and optionalDockerfile/docker-compose.yml) that the template generates.src/<id>/NOTES.md,src/<id>/README.md— docs (README is auto-generated, do not hand-edit; see below).
Build/validation helpers live in build/:
build/check-image-tags.ts— compares the image tags referenced by templates against the tags actually published by devcontainers/images. Run:npx tsx build/check-image-tags.ts <path-to-images-repo>.build/list-template-images.ts— lists every fully-qualified image a template produces.build/increment-patch.sh— bumps the patch version of everydevcontainer-template.json.
General conventions
- Formatting is enforced by Prettier using
.prettierrc(4 spaces, no tabs, single quotes in JS/TS). Runnpx prettier --write <files>after editing JSON/TS. - Do not hand-edit
src/*/README.md— they are regenerated by theUpdate Documentationworkflow. - Every
devcontainer-template.jsonmust retain non-empty string values for the mandatoryid,version, andnamefields. Never remove these fields. Preserve the existingidandnameunless the task explicitly requires changing them, and verify all three fields after editing the file. - Every change to a template must bump the
versionfield in that template'sdevcontainer-template.json(semantic versioning; a variant add/remove is a patch bump). - Keep changes minimal and scoped to the templates that actually need updating.
How templates reference container images
Templates pin a base image and expose its variants through a single string option
(usually named imageVariant). The image reference contains a placeholder that is
substituted with the chosen option value:
// src/java/.devcontainer/devcontainer.json
"image": "mcr.microsoft.com/devcontainers/java:3-${templateOption:imageVariant}"
// src/java/devcontainer-template.json
"options": {
"imageVariant": {
"type": "string",
"proposals": ["25-trixie", "21-trixie", "...", "8-bookworm"],
"default": "25-trixie"
}
}
So the concrete image tag is prefix + option value, e.g.
java:3- + 25-trixie = java:3-25-trixie. The proposals array is a curated
subset of {version}-{os} variants — it intentionally does not list every tag the
images repo publishes (floating tags such as java:3-25, OS-only tags such as
java:3-trixie, JDK/-jdk aliases, etc. are deliberately omitted).
Keeping templates in sync with devcontainers/images
When devcontainers/images adds or removes an
image variant, the affected templates must be updated. The scheduled
"Compare Templates against Images" workflow opens an issue (assigned to the coding agent)
containing the output of build/check-image-tags.ts, which classifies tags as:
- MISSING — referenced by a template but no longer published by images.
→ Action: remove that variant from the matching template's
options.imageVariant.proposals. Low-noise signal, but see the caveat below: a tag can be published by a differently-named image directory, so confirm it is genuinely gone from the images repo before removing it. - UNUSED — published by images but not referenced by any template.
→ Mostly intentional (aliases, floating/OS-only tags). Only add an entry when it is
a genuinely new
{version}-{os}variant that matches the template's existing naming convention (cross-check the image'ssrc/<image>/manifest.jsonvariantsarray in the images repo). Ignore floating/alias tags.
Editing rules
- Identify the template from the tag's image name (the part before
:). Map the tag back to a template by finding thesrc/*/.devcontainer/*file whose image reference shares that prefix. Some templates map to several images (e.g.phpandphp-mariadb).- A single image tag may be published from more than one image directory. The image
name (before
:) does not always match the images-repo directory that publishes the tag. Notably, thejavatemplate's8-trixie/8-bookwormvariants producejava:3-8-trixie/java:3-8-bookworm, which are published by the separatesrc/java-8image directory — not bysrc/java. Do not remove these variants just because they are absent fromsrc/java/manifest.json; verify againstsrc/java-8/manifest.jsonfirst. The same applies tojava-postgres, which builds on the samejavaimage.
- A single image tag may be published from more than one image directory. The image
name (before
- Removals (MISSING): delete the obsolete value from
proposalsonly after you have confirmed the tag is not published by any image directory (grep everysrc/*/manifest.jsonin the images repo for the tag, not just the one whose name matches the image prefix). Ifdefaultequals a removed value, setdefaultto the new newest variant (see ordering below). - Additions (UNUSED, only genuine new variants): insert the new value into
proposalsin the correct position (see ordering below).- If every variant for an image is reported MISSING, the image's pinned major in the
.devcontainerimage reference has changed (e.g.php:3-→php:4-). Update that prefix in the template'sdevcontainer.json/Dockerfileas well, then re-derive theproposals.
- If every variant for an image is reported MISSING, the image's pinned major in the
- Proposals ordering convention (match the existing files exactly):
- Group by OS, newest OS first. Observed priority:
trixie→bookworm→bullseye(Debian); for OS-named variants, Debian newest→oldest then Ubuntu newest→oldest (e.g.debian13,debian12,ubuntu24.04,ubuntu22.04). - Within an OS group, list versions descending (newest first).
- A floating major (e.g. Python's
3-trixie) comes first within its OS group.
- Group by OS, newest OS first. Observed priority:
- Default convention: the newest concrete version on the newest OS
(e.g.
25-trixie,1.26-trixie; Python uses the concrete3.14-trixie, not the floating3-trixie). - Do not touch options that are not image variants (e.g. cpp's
reinstallCmakeVersionFromSource, boolean feature toggles). - Preserve required metadata: image synchronization must not remove or rewrite the
top-level
idorname. Confirm thatid,version, andnameremain present as non-empty strings in every editeddevcontainer-template.json. - Bump
version(patch) in each editeddevcontainer-template.json.
Validating your change
Run the checker against the images repo and confirm there are no remaining MISSING tags for the templates you touched:
# Clone the images repo somewhere, then:
npx tsx build/check-image-tags.ts ../images
A successful sync produces zero MISSING tags. Remaining UNUSED tags are expected and
acceptable (they are mostly intentional aliases). Finish by running
npx prettier --write src/**/devcontainer-template.json.