devcontainer
Skill2 starsChanged 2 months agoMITView on GitHub
How to write, review, and secure Dev Container configuration per the Development Container Specification (https://containers.dev/, https://containers.dev/implementors/json_reference/) - project-agnostic. Covers devcontainer.json (locations, every property, image/Dockerfile/Compose scenarios, lifecycle scripts, variables, ports, customizations); Features (devcontainer-feature.json, options-to-env-vars, dependsOn/installsAfter ordering); finding and vetting trustworthy Features (the containers.dev index, trust tiers, auditing install.sh and inherited privileges, pinning, lockfile, Dependabot); authoring, testing and publishing Features (devcontainer features test, devcontainers/action); Templates; OCI distribution; and image metadata merging. Use when writing or reviewing a devcontainer.json, choosing or auditing a third-party Feature, building or publishing a Feature or Template, debugging install order or options, or setting up a reproducible dev environment for VS Code, Codespaces, DevPod, or similar.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- Cogni-AI-OU/cogni-ai-agent-skillstheir own version, first seen May 19, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- Cogni-AI-OU/cogni-ai-agent-skills★ 4same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository23 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- adrSkill
- cloudeventsSkill
- container-imagesSkill
- conventionalcommitsSkill
- core-principlesSkill
- dependabotSkill
- docsSkill
- engineering-practicesSkill
- gherkinSkill
- github-actionsSkill
- helm-chartsSkill
- jsonapiSkill
- json-schemaSkill
- keepachangelogSkill
- mkdocsSkill
- openapiSkill
- owasp-asvsSkill
- rfc9457Skill
- semverSkill
- skillSkill
- structured-loggingSkill
- terraform-providerSkill
The file
Files
Dev Containers
The Development Container Specification defines metadata — chiefly a
devcontainer.json file — that enriches an OCI container with what's needed
to develop inside it: how to build or reach the container, environment
variables, mounts, lifecycle commands, and tool-specific customizations.
Full spec at containers.dev; the implementor-facing
detail this skill is built from lives at
containers.dev/implementors/spec
and containers.dev/implementors/json_reference.
Reference implementation: devcontainers/cli.
Spec source/history: github.com/devcontainers/spec.
Three things share this one spec, and most confusion is about telling them apart:
devcontainer.json— describes one environment directly (this file's properties — see references/json-reference.md).- Dev Container Features — self-contained, shareable install code +
config, referenced by ID under
features— see references/features.md. - Dev Container Templates — a starter
.devcontainer/folder + options, dropped into a new or existing project — see references/templates.md.
The core idea
A dev container is described by scenario (image, Dockerfile, or Docker Compose) plus a common set of properties layered on top. Exactly one scenario applies, and each has its own required property:
| Scenario | Required property | Notes |
| Image | image | Pull-only, no build step. |
| Dockerfile | build.dockerfile | Path relative to devcontainer.json. build.context/args/options/target/cacheFrom control the build. |
| Docker Compose | dockerComposeFile + service | service names the main container all tooling attaches to. image/Dockerfile properties aren't needed — Compose already has them. |
Everything else — features, lifecycle scripts, remoteEnv, mounts,
customizations, etc. — applies on top of whichever scenario is chosen.
The full property table is in
references/json-reference.md.
Quick example
// .devcontainer/devcontainer.json
{
"name": "My Project",
"image": "mcr.microsoft.com/devcontainers/base:bookworm",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "20" },
"ghcr.io/devcontainers/features/github-cli": {}
},
"forwardPorts": [3000],
"postCreateCommand": "npm install",
"customizations": {
"vscode": { "extensions": ["dbaeumer.vscode-eslint"] }
}
}devcontainer.json (JSON-with-Comments) is looked up, in order of
precedence, at .devcontainer/devcontainer.json, .devcontainer.json, or
one level down at .devcontainer/<folder>/devcontainer.json — a tool should
let the user pick when more than one exists.
Where to look
| Reference | Covers |
| references/json-reference.md | Every devcontainer.json property: general + image/Dockerfile-specific + Compose-specific, lifecycle scripts (string/array/object forms, waitFor), port attributes, hostRequirements (incl. gpu), ${...} variable substitution, the declarative secrets property |
| references/features.md | devcontainer-feature.json authoring, the options → env var contract, referencing a Feature (OCI/tarball/local), install ordering (dependsOn, installsAfter, overrideFeatureInstallOrder), Feature lifecycle hooks, ${devcontainerId}, renaming/deprecating a Feature |
| references/using-features.md | Finding Features and deciding which to trust: the containers.dev index (listing ≠ review), trust tiers, vetting install.sh and inherited privileged/capAdd/mounts, pinning tags vs version options, lockfile + devcontainer upgrade/outdated, Dependabot, vendoring, the reference collection at a glance, docker-in-docker vs docker-outside-of-docker |
| references/feature-authoring.md | Writing a robust install.sh (distro/arch detection, idempotency, _REMOTE_USER, verifying downloads), devcontainer features test (autogenerated/scenario/duplicate/global), publishing with devcontainers/action, getting listed on containers.dev |
| references/templates.md | devcontainer-template.json authoring, the options string-replacement model, optionalPaths, referencing a Template |
| references/distribution.md | Packaging Features/Templates as tarballs, OCI registry distribution, devcontainer-collection.json, locally-referenced Features, the devcontainer-lock.json lockfile |
| references/lifecycle-and-tools.md | The environment lifecycle (init → create → post-create → stop/resume), image metadata (devcontainer.metadata label) merge logic, users, environment variable classes, mounts, and the customizations namespace pattern (VS Code, Codespaces, secrets) |
Gotchas
featuresvalues aren't always objects. A bare string is shorthand for{"version": "<string>"}—"go": "1.18"and"go": {"version": "1.18"}are equivalent. An empty object{}means "use this Feature's defaults."- A Feature is root-level build code plus runtime flags you inherit.
Being listed on containers.dev is not a review. Prefer
ghcr.io/devcontainers/features/*, then vendor-published collections, and readinstall.shand the manifest (privileged,capAdd, host mounts) before adopting anything else — see references/using-features.md. - A Feature/Template reference without a version tag implicitly means
:latest. Pin (:1,:1.2.3, or@sha256:...) for reproducibility — see the lockfile. dependsOnandinstallsAfterare not interchangeable.dependsOnis recursive and adds the dependency Feature to the install set even if the user never referenced it.installsAfteronly reorders Features already queued for install and is not recursive; a Feature named there that nobody asked for is silently ignored, not pulled in.- String vs. array vs. object changes execution, not just syntax, for
every lifecycle command and
postAttachCommand/etc.: a string goes through/bin/sh(so&&, quoting, and shell expansion apply); an array runs the executable directly with no shell (quotes in arguments are passed through literally, not stripped); an object runs each of its values in parallel. See references/json-reference.md. containerEnvvs.remoteEnvis a rebuild-cost tradeoff, not a synonym pair.containerEnvis baked into the container (visible to every process, including the entrypoint) and needs a rebuild to change.remoteEnvis applied by the supporting tool to the processes it starts (terminals, tasks,devcontainer exec) and can change without a rebuild — but isn't visible to the container's own entrypoint.${containerEnv:VAR}can be read from within aremoteEnvvalue to extend rather than replace (e.g. appending toPATH).workspaceMountrequiresworkspaceFolder(and vice versa) for image/Dockerfile scenarios — they're set as a pair, not independently. Docker Compose scenarios use the Compose file's ownvolumes/mountsinstead ofworkspaceMount.forwardPortsandappPortsolve different problems.forwardPortsmakes a port reachable from the host without the app needing to listen on anything butlocalhostinside the container.appPortpublishes the port (Docker-p), which requires the app to listen on0.0.0.0— and published ports don't behave likelocalhostto an app that only trusts loopback callers.- Image metadata merge order matters for "last value wins" properties
(
remoteUser,userEnvProbe,shutdownAction, …): thedevcontainer.jsonon disk is always applied last, after every Feature's metadata — a user's local file wins conflicts with any Feature, always. - Feature/Template IDs are case-insensitive but should be authored and compared as lowercase. Don't rely on casing to distinguish two references — normalize before comparing.
- The
secretsproperty indevcontainer.jsononly declares which secrets a project wants (name + description + docs URL) — it never holds a secret's value. Actual values are supplied out-of-band by the supporting tool (a secrets file, OS keychain, cloud secret store). Don't treat a documentedsecretsblock as a place to put real credentials, and don't treatremoteEnvas secret-safe just because it isn't baked into the image.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

