Skip to content

feat(devcontainer): refresh dev image and auto-update Claude Code#154

Open
dpage wants to merge 4 commits into
mainfrom
feat/devcontainer-claude-code-auto-update
Open

feat(devcontainer): refresh dev image and auto-update Claude Code#154
dpage wants to merge 4 commits into
mainfrom
feat/devcontainer-claude-code-auto-update

Conversation

@dpage

@dpage dpage commented May 7, 2026

Copy link
Copy Markdown
Member

Summary

  • Rebase the dev container on mcr.microsoft.com/devcontainers/go:2-1.25-trixie and replace the Node/docker-in-docker features with the github-cli and claude-code devcontainer features.
  • Bind-mount the host's ~/.config/gh, ~/.claude/commands, and ~/.claude/settings.json into the container, pass GH_TOKEN through, and forward the Vite (5173), docs (8000), and MCP (8080) ports.
  • On postCreateCommand, symlink the mounted Claude config under ~/.claude, add a claude --dangerously-skip-permissions alias, and auto-update @anthropic-ai/claude-code via sudo env "PATH=$PATH" npm update -g … so the update can write to the root-owned global node_modules while still locating the nvm-managed npm.

Test plan

  • Rebuild the dev container from a clean state and confirm postCreateCommand completes without the prior EACCES / npm: command not found errors.
  • Verify claude --version inside the container reflects the latest published release after rebuild.
  • Confirm gh auth status works inside the container (mounted gh config + GH_TOKEN).
  • Confirm Vite (5173), docs (8000), and MCP (8080) port-forward labels appear in the Ports panel.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated the development container base image and swapped in GitHub CLI and Claude integrations.
    • Persistently bind-mount local GitHub CLI and Claude configuration into the container for seamless access.
    • Added startup/linking steps and a shell alias to simplify invoking Claude, plus an attach-time notice explaining alias behavior.
    • Made port forwarding explicit for common dev ports and enabled per-port notifications.

Review Change Stack

Updates the development container to base on Go 1.25 Trixie, add the
Claude Code devcontainer feature, mount the host's gh config and Claude
commands/settings into the container, forward the dev/docs/MCP ports,
and pass GH_TOKEN through.

postCreateCommand symlinks the mounted Claude config into ~/.claude,
adds a `claude --dangerously-skip-permissions` alias, and runs
`sudo env "PATH=$PATH" npm update -g @anthropic-ai/claude-code` so the
update can write to the root-owned global node_modules while still
locating the nvm-managed npm binary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 04d42053-f8a5-4054-adb6-91813a713164

📥 Commits

Reviewing files that changed from the base of the PR and between fbb6092 and 6d95660.

📒 Files selected for processing (1)
  • .devcontainer/dev/devcontainer.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • .devcontainer/dev/devcontainer.json

Walkthrough

Updates .devcontainer/dev/devcontainer.json: switches to a Go devcontainer image with github-cli and claude-code features, adds host bind mounts for GH and Claude files, replaces lifecycle commands to link Claude files, add a claude alias and update @anthropic-ai/claude-code, and makes forwarded ports explicit with labels and notifications.

Changes

Devcontainer Configuration Update

Layer / File(s) Summary
Container Features
.devcontainer/dev/devcontainer.json
Replaces base image and swaps node and docker-in-docker features for github-cli and claude-code (both latest).
File Mounts and Persistence
.devcontainer/dev/devcontainer.json
Adds bind mounts for ~/.config/gh and Claude host commands/settings.json into /home/vscode (Claude mounts readonly).
Lifecycle commands and Claude CLI
.devcontainer/dev/devcontainer.json
Replaces postCreateCommand with commands that link mounted Claude host files into ~/.claude, append a claude alias using --dangerously-skip-permissions, and run npm global update for @anthropic-ai/claude-code; adds a postAttachCommand notice.
Port Forwarding
.devcontainer/dev/devcontainer.json
Adds explicit forwardPorts for 5173, 8000, 8080 and portsAttributes with labels and onAutoForward: notify for each port.
Commented placeholders
.devcontainer/dev/devcontainer.json
Retains commented guidance for customizations and remoteUser without active changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • pgEdge/pgedge-postgres-mcp#92: Both PRs modify .devcontainer/dev/devcontainer.json, changing devcontainer features and postCreate command behavior.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: updating the dev container image and auto-updating Claude Code, which directly aligns with the primary modifications in the devcontainer.json file.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/devcontainer-claude-code-auto-update

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production

codacy-production Bot commented May 7, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
.devcontainer/dev/devcontainer.json (1)

27-28: 💤 Low value

Stale template comments are now misleading.

The commented-out "features": {} (line 28) suggests features aren't configured, but they are (lines 7–15). Similarly, the commented-out "postCreateCommand": "go version" (line 48) shadows the active postCreateCommand on line 25. Both should be removed.

🧹 Suggested cleanup
-       // Features to add to the dev container. More info: https://containers.dev/features.
-       // "features": {},
-
         // Use 'forwardPorts' to make a list of ports inside the container available locally.
-       // Use 'postCreateCommand' to run commands after the container is created.
-       // "postCreateCommand": "go version",
-
         // Configure tool-specific properties.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/dev/devcontainer.json around lines 27 - 28, Remove the stale
commented template properties that are misleading: delete the commented-out
"features": {} entry and the commented-out "postCreateCommand": "go version" so
only the active "features" block (lines with the actual features) and the active
postCreateCommand remain; search for the literal strings "features": {} and
"postCreateCommand": "go version" in .devcontainer/dev/devcontainer.json and
remove their commented instances.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devcontainer/dev/devcontainer.json:
- Line 25: The postCreateCommand currently force-adds an alias 'alias
claude="claude --dangerously-skip-permissions"' into ~/.bashrc which silently
disables safety prompts; remove that hardcoded alias from the
"postCreateCommand" invocation and instead implement an opt-in flow: either (A)
append a visible commented snippet or instructions to ~/.bashrc (not an active
alias) that explain how to enable the flag manually, and add a postAttachCommand
that prints a clear one-time notice about the bypass and how to opt in, or (B)
document the opt-in step in README and leave no changes to ~/.bashrc; update any
references to the alias in the repo accordingly and ensure the unique string
alias claude="claude --dangerously-skip-permissions" is no longer silently
injected.
- Line 19: The devcontainer bind uses
"source=${localEnv:HOME}/.claude/settings.json,target=/home/vscode/.claude-host/settings.json,type=bind,readonly"
which will fail or create a host dir if the file is missing; update
initializeCommand to check for the existence of
${localEnv:HOME}/.claude/settings.json and either create a sensible default file
or emit a clear error and abort container start, or alternatively make the
postCreateCommand symlink conditional (only create the symlink if the target
file exists) so the container start won't fail or corrupt the host filesystem.
- Around line 21-24: The initializeCommand export of GH_TOKEN won't propagate to
containerEnv because localEnv is resolved before initializeCommand runs; fix by
having initializeCommand write the token to a file (e.g., create a .env with
GH_TOKEN=<token>) and then pass that file into the container via runArgs (e.g.,
--env-file .env) so the container receives GH_TOKEN, or alternatively remove
initializeCommand and containerEnv and rely on the existing ~/.config/gh
bind-mount for authentication; adjust the keys initializeCommand, containerEnv,
GH_TOKEN, runArgs and the .env filename accordingly.

---

Nitpick comments:
In @.devcontainer/dev/devcontainer.json:
- Around line 27-28: Remove the stale commented template properties that are
misleading: delete the commented-out "features": {} entry and the commented-out
"postCreateCommand": "go version" so only the active "features" block (lines
with the actual features) and the active postCreateCommand remain; search for
the literal strings "features": {} and "postCreateCommand": "go version" in
.devcontainer/dev/devcontainer.json and remove their commented instances.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a77f92dc-2d2a-47db-b708-150b891cf9ef

📥 Commits

Reviewing files that changed from the base of the PR and between bfbef42 and 79085b1.

📒 Files selected for processing (1)
  • .devcontainer/dev/devcontainer.json

Comment thread .devcontainer/dev/devcontainer.json
Comment thread .devcontainer/dev/devcontainer.json Outdated
Comment thread .devcontainer/dev/devcontainer.json Outdated
- Drop trailing comma after the 8080 portsAttributes entry so the
  Jackson Linter (strict JSON) stops flagging line 45.
- Make the ~/.claude/settings.json symlink in postCreateCommand
  conditional on the bind-mounted file existing, so machines without
  a host-side settings.json do not start with a dangling symlink.
- Replace the broken initializeCommand/containerEnv GH_TOKEN dance
  (localEnv is resolved before initializeCommand runs, so the export
  never reached the container) with an export appended to ~/.bashrc
  that uses the already bind-mounted ~/.config/gh credentials.
- Surface the claude --dangerously-skip-permissions alias via a new
  postAttachCommand notice and document the unalias / direct binary
  escape hatch, so the bypass is no longer silently in effect.
- Remove the stale commented-out template stubs ("features": {} and
  "postCreateCommand": "go version") that no longer matched reality.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
.devcontainer/dev/devcontainer.json (1)

18-19: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Optional Claude bind mounts can still block container startup.

Line 18 and Line 19 are bind mounts, so those host paths must exist before the container starts. The if [ -f ... ] check in postCreateCommand runs too late; a machine without ~/.claude/commands or ~/.claude/settings.json will fail during startup before that script executes.

How does the devcontainer.json "mounts" field map to Docker bind mounts, and what happens when a bind mount source path like ~/.claude/commands or ~/.claude/settings.json does not exist on the host?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devcontainer/dev/devcontainer.json around lines 18 - 19, The two entries in
.devcontainer/dev/devcontainer.json under "mounts" are translated to Docker bind
mounts (source=${localEnv:HOME}/.claude/commands and
source=${localEnv:HOME}/.claude/settings.json) and Docker will try to mount
those host paths at container start — if the host file/path doesn't exist the
bind will fail and block startup. Fix this by removing those unconditional bind
mounts and instead handle them at runtime: delete the two mount lines and add
logic in postCreateCommand (or postStartCommand) to check for
${localEnv:HOME}/.claude/commands and ${localEnv:HOME}/.claude/settings.json and
copy or link them into /home/vscode/.claude-host only when present, or document
that users must create those host files; reference the exact mount entries shown
("source=${localEnv:HOME}/.claude/commands,target=/home/vscode/.claude-host/commands,type=bind,readonly"
and
"source=${localEnv:HOME}/.claude/settings.json,target=/home/vscode/.claude-host/settings.json,type=bind,readonly")
when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devcontainer/dev/devcontainer.json:
- Line 21: The current postCreateCommand appends "export GH_TOKEN=$(gh auth
token ...)" to ~/.bashrc which doesn't expose GH_TOKEN to non-interactive
processes; instead remove that append and set GH_TOKEN using devcontainer.json's
remoteEnv or containerEnv so the variable is available container-wide; update
the postCreateCommand (the "postCreateCommand" entry) to stop relying on
~/.bashrc and, if you need to obtain the token at creation time via gh, capture
it in the devcontainer build step and populate remoteEnv/containerEnv GH_TOKEN
accordingly so VS Code tasks and extensions can read it.

---

Duplicate comments:
In @.devcontainer/dev/devcontainer.json:
- Around line 18-19: The two entries in .devcontainer/dev/devcontainer.json
under "mounts" are translated to Docker bind mounts
(source=${localEnv:HOME}/.claude/commands and
source=${localEnv:HOME}/.claude/settings.json) and Docker will try to mount
those host paths at container start — if the host file/path doesn't exist the
bind will fail and block startup. Fix this by removing those unconditional bind
mounts and instead handle them at runtime: delete the two mount lines and add
logic in postCreateCommand (or postStartCommand) to check for
${localEnv:HOME}/.claude/commands and ${localEnv:HOME}/.claude/settings.json and
copy or link them into /home/vscode/.claude-host only when present, or document
that users must create those host files; reference the exact mount entries shown
("source=${localEnv:HOME}/.claude/commands,target=/home/vscode/.claude-host/commands,type=bind,readonly"
and
"source=${localEnv:HOME}/.claude/settings.json,target=/home/vscode/.claude-host/settings.json,type=bind,readonly")
when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: acd3d016-91c6-4b6c-9caa-69379017b7a5

📥 Commits

Reviewing files that changed from the base of the PR and between 79085b1 and fdfb9ea.

📒 Files selected for processing (1)
  • .devcontainer/dev/devcontainer.json

Comment thread .devcontainer/dev/devcontainer.json Outdated
CodeRabbit correctly noted that appending `export GH_TOKEN=...` to
~/.bashrc only sets the variable for interactive shells; VS Code
tasks, extensions, and other non-interactive processes never see it.

No tool inside the dev container actually reads $GH_TOKEN — every
reference in the repo is in GitHub Actions workflows that run on
hosted runners, not here. The bind-mounted ~/.config/gh already
authenticates the `gh` CLI itself, and consumers that need the raw
token can call `gh auth token` explicitly.

Remove the bashrc export and add a short comment documenting how
auth flows so the next reader does not re-add a plumbing line that
does not work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devcontainer/dev/devcontainer.json:
- Line 24: The postCreateCommand currently appends "alias claude=\"claude
--dangerously-skip-permissions\"" to ~/.bashrc unconditionally, causing
duplicate entries on rebuilds; modify the postCreateCommand so it checks for the
exact alias line first (e.g., grep -qxF or test with grep) and only appends it
if missing, ensuring the alias addition is idempotent while leaving the rest of
the command sequence (mkdir/ln -sf/npm update) unchanged and still referencing
the same alias text used in the current command.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 25b4f174-2898-45f2-b3a8-e2ed5c0ccf6f

📥 Commits

Reviewing files that changed from the base of the PR and between fdfb9ea and fbb6092.

📒 Files selected for processing (1)
  • .devcontainer/dev/devcontainer.json

Comment thread .devcontainer/dev/devcontainer.json Outdated
Guard the bashrc alias append with `grep -qxF` so re-running
postCreateCommand on container rebuilds does not stack duplicate
`alias claude="claude --dangerously-skip-permissions"` lines.

Addresses the CodeRabbit follow-up on fbb6092.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant