Skip to content

fix(devcontainer): sync to python_template's zero-build config - #9

Open
blooop wants to merge 3 commits into
mainfrom
fix/devcontainer-zero-build
Open

fix(devcontainer): sync to python_template's zero-build config#9
blooop wants to merge 3 commits into
mainfrom
fix/devcontainer-zero-build

Conversation

@blooop

@blooop blooop commented Aug 24, 2026

Copy link
Copy Markdown
Owner

The devcontainer now pulls ghcr.io/blooop/python_template/devcontainer:latest
instead of building the image locally.

  • The duplicate claude-code features block is gone. The feature is baked into
    that image already (ci/devcontainer.json is what CI builds it from, and that
    declares ../claude-code), so declaring it here made the spec build a derived
    image on the first launch of every branch and reinstall what the pulled image
    already had.
  • --network=host is gone. A container per branch is the point of dl, and
    host networking undoes it: every port a dev server binds becomes a host port,
    so two branches collide on the first one they share.
  • The ~/.ssh and ~/.config/gh mounts are gone. dl supplies GH_TOKEN, and
    the gh mount never worked in the first place because gh keeps its token in the
    system keyring, so the mounted hosts.yml carried no oauth_token.
  • name moved to the end of the file. It is the only per-repo line here, and
    sitting next to the image block -- the block the template changes most -- it
    conflicted on every pixi run update-from-template-repo.

The tree is byte-identical to blooop/python_template#170 apart from that name.

Depends on blooop/python_template#170. The published image already exists and is
public, so this works before that merges.

🤖 Generated with Claude Code

Summary by Sourcery

Adopt the shared zero-build development image while improving branch isolation, Claude authentication, and repository initialization.

New Features:

  • Add a CI-specific devcontainer configuration for building and publishing the shared development image.
  • Add repository post-create setup that initializes dependencies, SSH host verification, and optional project tasks.

Bug Fixes:

  • Prevent branch devcontainers from rebuilding derived images, sharing host networking, or relying on ineffective GitHub and SSH configuration mounts.
  • Avoid devcontainer setup failures in repositories that do not define optional Pixi tasks.

Enhancements:

  • Align the development container with the shared zero-build Python template image and update Pixi to v0.75.0.
  • Simplify Claude Code configuration by sharing the host configuration directory and document the resulting authentication workflow and security trade-offs.
  • Update Claude Code installation and troubleshooting documentation for the published-image workflow.

CI:

  • Define the CI devcontainer configuration used to build the published development image with the Claude Code feature.

Documentation:

  • Revise Claude Code usage, authentication, mounting, troubleshooting, and security documentation to reflect the shared published image and read-write configuration mount.

Chores:

  • Reorganize devcontainer configuration to keep repository-specific settings separate from template-managed settings.

The devcontainer now pulls ghcr.io/blooop/python_template/devcontainer:latest
instead of building the image locally.

- The duplicate claude-code `features` block is gone. The feature is baked into
  that image already (ci/devcontainer.json is what CI builds it from, and that
  declares ../claude-code), so declaring it here made the spec build a derived
  image on the first launch of every branch and reinstall what the pulled image
  already had.
- `--network=host` is gone. A container per branch is the point of `dl`, and
  host networking undoes it: every port a dev server binds becomes a host port,
  so two branches collide on the first one they share.
- The `~/.ssh` and `~/.config/gh` mounts are gone. `dl` supplies GH_TOKEN, and
  the gh mount never worked in the first place because gh keeps its token in the
  system keyring, so the mounted hosts.yml carried no oauth_token.
- `name` moved to the end of the file. It is the only per-repo line here, and
  sitting next to the image block -- the block the template changes most -- it
  conflicted on every `pixi run update-from-template-repo`.

The tree is byte-identical to blooop/python_template#170 apart from that name.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @blooop, you have reached your weekly rate limit of 250000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR synchronizes the devcontainer with the template’s zero-build workflow by publishing a CI-built GHCR image, simplifying branch launch configuration, upgrading pixi-based Claude installation, and replacing individual Claude mounts with a shared read-write host configuration directory. Reviewers should focus on the CI image/launch-config relationship, feature path and build context correctness, and the deliberate security implications of exposing the entire host ~/.claude directory to containers.

Sequence diagram for launching a branch container with shared Claude credentials

sequenceDiagram
    participant User
    participant Launcher as dl
    participant GHCR
    participant Container
    participant HostClaude as Host ~/.claude

    User->>Launcher: launch branch
    Launcher->>GHCR: pull devcontainer:latest
    GHCR-->>Launcher: published image with claude-code
    Launcher->>Container: start container with GH_TOKEN
    Launcher->>Container: bind-mount ~/.claude
    Container->>HostClaude: read and refresh Claude credentials
Loading

File-Level Changes

Change Details Files
Switch branch devcontainers to consume the published zero-build image and keep repository-specific configuration minimal.
  • Add the GHCR image reference and move the per-repository name setting to the end of the launch configuration.
  • Remove local feature composition and host-networking arguments from the branch launch spec.
  • Add CI-only devcontainer configuration that builds the Dockerfile and includes the Claude Code feature before publishing.
.devcontainer/devcontainer.json
.devcontainer/ci/devcontainer.json
Align the local image definition and Claude Code installation with the template’s newer pixi-based toolchain.
  • Upgrade the bundled pixi version.
  • Remove Dockerfile setup that only supported SSH mounts.
  • Make feature installation Bash-based and robust under strict error handling, including pixi fallback setup and shellcheck annotations.
.devcontainer/Dockerfile
.devcontainer/claude-code/install.sh
Redesign Claude configuration sharing around a single live host bind mount and document the resulting authentication and security model.
  • Mount the host ~/.claude directory read-write and point Claude at it with CLAUDE_CONFIG_DIR.
  • Document host-side authentication, live credential refresh, workspace onboarding state, and optional host networking for container-side OAuth.
  • Explicitly describe that container code can modify host Claude settings, hooks, and credentials, and update troubleshooting and setup guidance accordingly.
.devcontainer/claude-code/README.md
.devcontainer/claude-code/TROUBLESHOOTING.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

The earlier commit on this branch removed the ~/.config/gh bind mount and
justified it with the claim that the mount never worked -- that `gh` keeps its
token in the system keyring, so the mounted hosts.yml carries no oauth_token.

That claim is false on this machine. ~/.config/gh/hosts.yml carries a real
oauth_token, and in a running container using that mount, with GH_TOKEN and
GITHUB_TOKEN unset, `gh auth status` reports:

    Logged in to github.com account blooop (/home/vscode/.config/gh/hosts.yml)

gh writes to a keyring only where one is available and falls back to the file
otherwise, so the keyring claim held for some environment but not this one, and
it got generalised into the config as if it always held.

Nothing broke under `dl`, which is why it went unnoticed: `dl` forwards
GH_TOKEN, devpod applies workspace env after the devcontainer's own, and the
env token wins wherever both are present. The entry paths that lost gh auth
they previously had are the non-`dl` ones -- a plain `devpod up`, and VS Code's
Reopen in Container. So the mount comes back.

The ~/.ssh removal is unaffected and stays removed. It was verified separately
in a live container: devpod forwards an ssh agent at a socket path of its own,
`ssh-add -l` lists the host key, and `git ls-remote` against a git@github.com:
origin succeeds with an empty ~/.ssh. The old hardcoded
SSH_AUTH_SOCK=/home/vscode/.ssh/agent.sock actively overrode that working
forwarded socket, so it stays gone too.
@blooop

blooop commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

Pushed a correction to this branch.

The earlier commit removed the ~/.config/gh bind mount on the grounds that it never worked -- that gh keeps its token in the system keyring, leaving the mounted hosts.yml without an oauth_token. That is false on this machine: hosts.yml carries a real oauth_token, and in a running container using the mount, with GH_TOKEN/GITHUB_TOKEN unset, gh auth status reports Logged in to github.com account blooop (/home/vscode/.config/gh/hosts.yml).

Nothing broke under dl because dl forwards GH_TOKEN and the env token wins. The entry paths that lost gh auth were the non-dl ones -- a plain devpod up and VS Code's Reopen in Container. So the mount is back.

The ~/.ssh removal is unaffected and stays removed: devpod forwards an ssh agent at its own socket path (verified live -- ssh-add -l lists the host key and git ls-remote succeeds with an empty ~/.ssh), and the old hardcoded SSH_AUTH_SOCK=/home/vscode/.ssh/agent.sock overrode that working socket.

…rek-install

Synced from blooop/python_template.

The previous postCreateCommand ended in `pixi run prek-install`. This repo does
not define that task, so `pixi run` exited 127, the lifecycle hook failed, and
container creation failed outright -- the workspace never came up. Found by
launching the container; neither JSON validation nor CI sees it.
postCreateCommand now calls .devcontainer/post-create.sh, which runs the task
only where it exists.

The script also seeds known_hosts. devpod forwards an ssh agent, so the host's
~/.ssh does not need mounting -- but the agent carries authentication, not host
identity, and on a fresh container the first git operation over an ssh remote
died with "Host key verification failed". Interactive users can click through
that; scripts, agents and in-container CI cannot.
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