Agent skill
setting-up-devcontainers
Generate devcontainer configurations for Claude Code development environments. Use when setting up development containers with Claude Code and optional Codex CLI. Automatically detects marketplace.json for plugin marketplace configurations.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/setting-up-devcontainers-taisukeoe-agentic-ai-skills-cr
Metadata
Additional technical details for this skill
- author
- Softgraphy GK
- version
- 0.2.0
SKILL.md
Setting Up Devcontainers for Claude Code
Generate complete .devcontainer/ configurations for Claude Code development environments with:
- Pre-installed Claude Code (+ optional Codex CLI built into Docker image)
- Persistent credentials and config via Docker volumes
- Marketplace mode (if marketplace.json exists): Auto-enabled plugins and skills
Quick Start
User: Set up a devcontainer for this project
Agent: I'll check for marketplace.json and generate the devcontainer configuration.
Workflow
Step 1: Detect Mode
Check for .claude-plugin/marketplace.json:
ls .claude-plugin/marketplace.json
Mode determination:
- Marketplace mode: If
marketplace.jsonexists → full plugin/skill setup - Generic mode: If not found → Claude Code environment (+ optional Codex CLI)
For Marketplace mode, extract:
name- Marketplace name (used for volume naming)plugins- Array of plugin definitions
For Generic mode, use:
- Project directory name for volume naming
Step 2: Ask About Codex CLI Support (Optional)
Ask the user explicitly:
Do you want to add Codex CLI (OpenAI) support alongside Claude Code?
- Yes: Adds Volta, Node.js, Codex CLI, and skill sync mechanism
- No (default): Claude Code only
If yes:
- Add Volta/Node.js/Codex CLI installation to Dockerfile (installed at build time)
- Add
~/.codex/volume mount for config persistence - Add
sync-codex-skills.shscript (copies skills to~/.codex/skills/) [Marketplace mode only] - Add Codex sync call to
post-create.sh[Marketplace mode only]
Note: Both Claude Code and Codex CLI are installed at Docker build time for faster container startup.
Step 3: Discover Plugins and Skills [Marketplace Mode Only]
Skip this step in Generic mode.
For each plugin in marketplace.json:
- Read
sourcepath (e.g.,"./plugins/plugin-name") - Check for
.claude-plugin/plugin.jsonin source directory - Find
skillspath from plugin.json or use./skills/default - List all SKILL.md files in skills directory
- Extract skill names from directory names
Build two lists:
enabledPlugins:{"plugin-name@marketplace-name": true, ...}allowedSkills:["Skill(skill-1)", "Skill(skill-2)", ...]
Step 4: Ask About Auto-Sync on Container Start [Marketplace Mode Only]
Skip this step in Generic mode.
Ask the user explicitly:
Do you want to automatically reinstall the marketplace on every container start?
- Yes: Adds
postStartCommandto runreinstall-marketplace.shautomatically- No (recommended for stable development): Run manually when needed
Note: This is a workaround for Claude Code not detecting local plugin changes. Running on every start adds ~5-10 seconds delay.
Step 5: Generate Files from Templates
Use the templates in templates/ directory, substituting placeholders:
Common Placeholders
| Placeholder | Value |
|---|---|
{{PROJECT_NAME}} |
Marketplace name (if exists) or project directory name |
{{PROJECT_DIR}} |
Project directory name |
{{CODEX_VOLUME_MOUNT}} |
If Codex: ,\n "source=codex-config-{{PROJECT_NAME}},..." else: empty |
{{VOLTA_ENV_BLOCK}} |
If Codex: ENV VOLTA_HOME=... ENV PATH=... else: empty |
{{CODEX_INSTALL_BLOCK}} |
If Codex: Volta/Codex RUN command, else: empty |
{{CODEX_DIR_LIST}} |
If Codex: "$HOME/.codex" else: empty |
{{CODEX_ALIASES}} |
If Codex: Codex alias lines, else: empty |
{{CODEX_ALIAS_ECHO}} |
If Codex: echo " codex-f - codex --full-auto" else: empty |
{{DEVCONTAINER_READY_MESSAGE}} |
"Claude Code devcontainer ready!" or "Claude Code + Codex CLI devcontainer ready!" |
Marketplace Mode Placeholders
| Placeholder | Value |
|---|---|
{{ENABLED_PLUGINS}} |
Object entries like "plugin@market": true |
{{ALLOWED_SKILLS}} |
Array entries like "Skill(name)" |
{{PLUGIN_INSTALL_COMMANDS}} |
Plugin install commands (with ` |
{{CODEX_SETUP_BLOCK}} |
If Codex and Marketplace mode: Codex skill sync in post-create.sh, else: empty |
{{CODEX_SYNC_BLOCK}} |
If Codex: Codex sync in reinstall-marketplace.sh, else: empty |
{{POST_START_COMMAND}} |
If auto-sync: ,\n "postStartCommand": "bash .devcontainer/reinstall-marketplace.sh" else: empty |
{{SETTINGS_BLOCK}} |
Shell commands to create settings.json with enabledPlugins/allowedSkills |
{{MARKETPLACE_REGISTER_BLOCK}} |
Marketplace registration and plugin install commands |
{{MARKETPLACE_SYNC_HINT}} |
echo "To sync marketplace: bash .devcontainer/reinstall-marketplace.sh" |
Generic Mode Placeholders
| Placeholder | Value |
|---|---|
{{POST_START_COMMAND}} |
empty (no postStartCommand) |
{{SETTINGS_BLOCK}} |
empty (no plugin settings needed) |
{{MARKETPLACE_REGISTER_BLOCK}} |
empty (no marketplace registration) |
{{CODEX_SETUP_BLOCK}} |
empty (no skill sync needed) |
{{MARKETPLACE_SYNC_HINT}} |
empty |
Templates:
- devcontainer.json.template - Container configuration
- Dockerfile.template - Ubuntu + dependencies
- post-create.sh.template - Initial setup
- reinstall-marketplace.sh.template - Marketplace sync (Marketplace mode only)
- sync-codex-skills.sh.template - Codex skill sync (Marketplace mode + Codex only)
Conditional logic:
- Generic mode: Omit reinstall-marketplace.sh and sync-codex-skills.sh
- If user chose no auto-sync: Remove
postStartCommandfrom devcontainer.json - If user chose no Codex: Omit Volta/Codex sections
Step 6: Write Files and Set Permissions
- Create
.devcontainer/directory if not exists - Write all generated files (without
.templatesuffix) - Make shell scripts executable:
chmod +x .devcontainer/*.sh
Step 7: Provide Usage Instructions
Generic mode:
Devcontainer files created in .devcontainer/
To use:
1. Open project in VS Code
2. Click "Reopen in Container" when prompted
(or use Command Palette: "Dev Containers: Reopen in Container")
3. Run 'claude' on first use to complete initial setup
Your credentials persist in Docker volumes.
Marketplace mode:
Devcontainer files created in .devcontainer/
To use:
1. Open project in VS Code
2. Click "Reopen in Container" when prompted
(or use Command Palette: "Dev Containers: Reopen in Container")
3. Run 'claude' on first use to complete initial setup
Your credentials persist in Docker volumes.
To manually sync marketplace changes:
bash .devcontainer/reinstall-marketplace.sh
Generated File Locations
Generic mode:
.devcontainer/
├── devcontainer.json # Container configuration
├── Dockerfile # Ubuntu + Claude Code (+ Volta/Codex if enabled)
└── post-create.sh # Initial setup (config, aliases)
Marketplace mode:
.devcontainer/
├── devcontainer.json # Container configuration
├── Dockerfile # Ubuntu + Claude Code (+ Volta/Codex if enabled)
├── post-create.sh # Initial setup (config, marketplace, Codex sync)
├── reinstall-marketplace.sh # Marketplace sync script (+ Codex sync if enabled)
└── sync-codex-skills.sh # Codex skill sync (only if Codex enabled)
Key Configuration Details
Volume Strategy
Uses named Docker volumes plus a symlink for complete persistence:
Docker Image (built once):
├── ~/.local/bin/claude # Claude Code binary
└── ~/.volta/ # Volta + Node.js + Codex CLI (if enabled)
Volume 1: claude-config-${PROJECT_NAME} → ~/.claude/
├── .home-claude.json # Setup state (symlink target)
├── .credentials.json # Auth tokens
├── settings.json # User settings
└── plugins/ # Plugin data (Marketplace mode)
Volume 2: claude-data-${PROJECT_NAME} → ~/.local/share/claude/
└── (Claude Code data) # Session data, etc.
Volume 3 (if Codex enabled): codex-config-${PROJECT_NAME} → ~/.codex/
├── config.toml # Codex CLI configuration
├── sessions/ # Session data
└── skills/ # Synced skills from marketplace (Marketplace mode)
Symlink (created by post-create.sh):
~/.claude.json → ~/.claude/.home-claude.json
Why this architecture?
| Location | Purpose | Persistence Method |
|---|---|---|
~/.local/bin/claude |
Claude Code binary | Docker image (fast startup) |
~/.volta/ |
Codex CLI binary | Docker image (fast startup) |
~/.claude/ |
Config, credentials, settings | Volume mount |
~/.local/share/claude/ |
Claude session data | Volume mount |
~/.claude.json |
Initial setup state | Symlink to volume |
~/.codex/ (optional) |
Codex config, sessions, skills | Volume mount |
Important: ~/.claude.json cannot be directly mounted as a volume (Docker creates a directory instead of a file). The symlink approach allows the file to persist inside the ~/.claude/ volume.
Shell Alias
The setup creates a persistent alias file in the volume:
post-create.shcreates~/.claude/.shell-aliases(persists in volume)post-create.shaddssourceline to.zshrc(both modes, with duplicate protection)reinstall-marketplace.shalso addssourceline to.zshrcon every start (Marketplace mode only)
# ~/.claude/.shell-aliases (persisted)
alias claude-y='claude --dangerously-skip-permissions'
# If Codex enabled:
alias codex-f='codex --full-auto'
This survives container rebuilds because the alias file is stored in the volume.
Plugin Format [Marketplace Mode Only]
enabledPlugins must be object format (not array):
{
"enabledPlugins": {
"plugin-a@marketplace": true,
"plugin-b@marketplace": true
}
}
Marketplace Sync (Workaround) [Marketplace Mode Only]
reinstall-marketplace.sh is a workaround for Claude Code not automatically detecting local plugin/skill changes.
What it does:
- Removes and re-adds the marketplace
- Reinstalls all enabled plugins
When to run:
- Manually after editing SKILL.md files:
bash .devcontainer/reinstall-marketplace.sh - Or automatically via
postStartCommand(if user opted in)
Error Handling
| Error | Cause | Solution |
|---|---|---|
| No plugins found | Empty plugins array | Warn user, generate minimal config |
| Source path invalid | Plugin source doesn't exist | Report error, skip invalid plugins |
| Existing .devcontainer/ | Files already present | Ask before overwriting |
| GID/UID 1000 already exists | Ubuntu base image has existing user | Use getent to detect and rename existing user |
| Permission denied on config | Volume owned by root | Use sudo chown in post-create.sh |
| claude: command not found | PATH not set | Export PATH="$HOME/.local/bin:$PATH" in scripts |
| EISDIR on ~/.claude.json | Volume mounted as directory | Remove directory, use symlink instead |
| JSON Parse error: Unexpected EOF | Empty ~/.claude.json file | Initialize with {} not empty file |
| Raw mode not supported | Plugin commands in non-interactive shell | Only run plugin commands if setup complete |
| Login required after rebuild | ~/.claude.json not persisted | Symlink to file inside volume |
References
Didn't find tool you were looking for?