Skip to content

My personal dev container template(s), builds off the base image defined in my dev-container-base repo: https://github.com/peter-wagstaff/dev-container-base

License

Notifications You must be signed in to change notification settings

peter-wagstaff/dev-container-generic

Repository files navigation

devcontainer-generic

Generic dev container config built on devcontainer-base. Copy this directory into your project as .devcontainer/ — no Docker build needed.

Prerequisites

  • Docker (or Docker Desktop)
  • VS Code with the Dev Containers extension

Setup

  1. Build the base image first (one-time): cd .devcontainer-base && ./build.sh
  2. Pull into your project:
    git clone git@github.com:peter-wagstaff/dev-container-generic.git your-project/.devcontainer
  3. Copy .env.example to .env and set your git profile (SSH key, name, email)
  4. Optionally add required external domains to firewall-domains.conf
  5. Optionally customize VS Code extensions and settings in devcontainer.json (defaults are ESLint, Prettier, GitLens)
  6. Open the project in VS Code and "Reopen in Container"

Git profile

The git identity (SSH key, name, email) is configured via .devcontainer/.env, which is gitignored. This lets each developer use their own GitHub account without modifying tracked files.

cp .devcontainer/.env.example .devcontainer/.env
# Edit .env with your profile

Available variables (see .env.example):

Variable Description
GIT_SSH_KEY SSH key filename from your ~/.ssh directory (e.g., id_ed25519)
GIT_USER_NAME Git commit author name
GIT_USER_EMAIL Git commit author email

All three are required. The container will fail to start with a clear error if any are missing.

Credential persistence

Claude Code and Codex credentials are persisted across container rebuilds via the agent-persistence devcontainer feature. It mounts a Docker volume at /mnt/agent-persistence and symlinks ~/.claude and ~/.codex into it. Login once and credentials survive rebuilds. Shell history is also persisted via a separate per-project volume.

The feature is configured in devcontainer.json under "features":

"features": {
  "ghcr.io/peter-wagstaff/devcontainer-features/agent-persistence:1": {
    "scope": "per-project"
  }
}

Scope options

Scope Behavior
shared (default) One volume across all containers — all projects share credentials and config
per-project Isolated subdirectory per dev container — credentials and config are separate per project

When using per-project scope, you must also add DEVCONTAINER_ID to your containerEnv in devcontainer.json (${devcontainerId} substitution doesn't work inside feature metadata):

"containerEnv": {
  "DEVCONTAINER_ID": "${devcontainerId}"
}

This is already configured in devcontainer.json.

Agent toggles

Option Default What it persists
claude true ~/.claude (Claude Code config, credentials, conversation history)
codex true ~/.codex (Codex config and credentials)
gemini true ~/.gemini and related caches
github-cli true ~/.config/gh (GitHub CLI auth)

Customization

Packages

If a project needs extra system packages, uncomment the build: block in docker-compose.yml (and comment out image:), then edit the Dockerfile:

USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
  <your-packages> \
  && apt-get clean && rm -rf /var/lib/apt/lists/*

Firewall domains

Add domains to firewall-domains.conf (one per line). These are merged with the base domains at container start.

Agent instructions

Edit scripts/GLOBAL_AGENTS.md to change the global instructions installed for both Claude Code and Codex. The setup script hashes this file — changes trigger a re-install on next container create.

Agent plugins and skills

Plugin/skill configuration for both agents is handled in scripts/setup-dev-container.sh.

Claude Code — the setup script seeds $CLAUDE_HOME/settings.json with two plugin marketplaces and their enabled plugins:

Plugin Marketplace
Context7 anthropics/claude-plugins-official
Superpowers obra/superpowers-marketplace

The settings file is only written if it doesn't already exist — once seeded, your runtime changes (enabling/disabling plugins, adding new ones) are preserved across rebuilds. To change the defaults for new containers, edit the settings.json heredoc in the setup script. To re-seed an existing container, delete $CLAUDE_HOME/settings.json and rebuild.

Codex — the setup script clones obra/superpowers into $CODEX_HOME/superpowers/ and symlinks its skills into ~/.agents/skills/superpowers/, where Codex auto-discovers them. Unlike Claude's settings, the superpowers repo is updated (git pull) on each setup run. Codex has no marketplace config — skills are found by directory scanning.

Container lifecycle

Phase What runs User
ENTRYPOINT firewall-entrypoint.shinit-firewall.shexec sleep infinity root (containerUser)
initializeCommand Ensures .env exists, prunes old devcontainer images host
postCreateCommand setup-dev-container.sh + container-readiness.sh dev (remoteUser)

The containerUser: root / remoteUser: dev split means the ENTRYPOINT (firewall setup) runs as root without sudo, while all developer shell sessions run as dev.

The container uses docker-compose.yml with image: devcontainer-base:latest and pull_policy: never so that the pre-built base image is used directly without a build step. Capabilities (NET_ADMIN, NET_RAW), env file, and volume mounts are declared in the compose file rather than devcontainer.json. Project-specific firewall domains are volume-mounted from firewall-domains.conf.

Scripts

  • scripts/initialize-host.sh — Runs on the host before each build. Ensures .env exists, registers the project in ~/.devcontainer-projects (for tracking orphaned volumes from deleted projects), and prunes dangling images.
  • scripts/setup-dev-container.sh — Configures git, SSH, agent instructions, plugins, npm deps. Reads git profile from env vars (GIT_SSH_KEY, GIT_USER_NAME, GIT_USER_EMAIL). Idempotent via hash cache (re-runs when the script or GLOBAL_AGENTS.md changes).
  • scripts/container-readiness.sh — Verifies required commands exist: git, make, python3, uv, node, npm, claude, codex.
  • scripts/GLOBAL_AGENTS.md — Shared instructions installed to both $CLAUDE_HOME/CLAUDE.md and $CODEX_HOME/AGENTS.md.

About

My personal dev container template(s), builds off the base image defined in my dev-container-base repo: https://github.com/peter-wagstaff/dev-container-base

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors