Skip to content

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

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

fix(devcontainer): sync to python_template's zero-build config#10
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.

This repo's devcontainer name was still python_template because rename_project.sh was never run here; pyproject.toml still says name = "python_template" and that is left alone as out of scope.

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

Modernize the development container and add integrated Claude Code tooling with persistent host-backed configuration.

New Features:

  • Add a local Claude Code Dev Container Feature with CLI installation, host configuration mounting, authentication setup, and troubleshooting guidance.
  • Add CI-specific devcontainer configuration for building the published development image.
  • Add post-create environment setup, SSH host-key initialization, and optional Pixi task execution.

Bug Fixes:

  • Prevent devcontainer setup failures caused by missing optional Pixi tasks and unavailable SSH host keys.
  • Ensure Claude configuration and credentials persist correctly across container rebuilds.

Enhancements:

  • Modernize the development container base image and upgrade Pixi.
  • Improve shell environment configuration for Pixi and Claude tooling.
  • Expand devcontainer configuration for reproducible development environments and shared Claude authentication.

Documentation:

  • Document Claude Code feature usage, authentication, mounts, troubleshooting, security considerations, and local iteration.

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 repository with the template’s zero-build devcontainer model: branch launches pull a prebuilt GHCR image with no derived feature installation or host networking, while CI builds that image using an added local Claude Code feature; the Dockerfile and supporting documentation/scripts are updated for the newer Ubuntu and Pixi versions.

File-Level Changes

Change Details Files
Switch branch development containers from local, per-launch image derivation to a prebuilt GHCR image.
  • Use the published python_template devcontainer image.
  • Move the per-repository name field away from template-managed image configuration.
  • Remove the duplicate Claude Code feature declaration and host-networking run argument.
  • Remove ineffective SSH and GitHub CLI configuration mounts while retaining token injection through dl.
.devcontainer/devcontainer.json
Align the container base image and Pixi runtime with the shared zero-build template.
  • Update the base image from Jammy to Ubuntu 24.04.
  • Upgrade Pixi from v0.32.1 to v0.75.0.
  • Add Pixi global and Claude shim environment paths to the user profile.
.devcontainer/Dockerfile
Add the local Claude Code Dev Container Feature used when publishing the shared image.
  • Install the claude-shim package through the blooop Pixi channel.
  • Resolve the target remote user and home directory across Dev Container environments.
  • Create Claude configuration directories and placeholder credential files with appropriate ownership and permissions.
  • Initialize the host-side ~/.claude directory before container creation.
  • Document feature metadata, usage, authentication, troubleshooting, security implications, and future publishing/composition options.
.devcontainer/ci/devcontainer.json
.devcontainer/claude-code/devcontainer-feature.json
.devcontainer/claude-code/install.sh
.devcontainer/claude-code/init-host.sh
.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