Repository navigation
fix(devcontainer): sync to python_template's zero-build config - #1126
Conversation
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.
Reviewer's GuideThe PR synchronizes the runtime devcontainer with python_template’s published zero-build image, moving Claude Code feature installation to the CI-built image, removing branch-conflicting host networking and ineffective credential mounts, and documenting the resulting shared ~/.claude authentication and security model. Sequence diagram for host-authenticated Claude Code startupsequenceDiagram
participant Host as Host machine
participant Config as Host ~/.claude
participant Container as Branch container
participant Claude as Claude Code
Host->>Claude: Authenticate on host
Claude->>Config: Write credentials
Container->>Config: Read live bind mount
Container->>Claude: Start with CLAUDE_CONFIG_DIR
Claude->>Config: Refresh credentials and workspace state
Flow diagram for concurrent branch container networkingflowchart LR
BranchA[Branch container A] -->|default bridge network| PortA[Branch-local dev server port]
BranchB[Branch container B] -->|default bridge network| PortB[Branch-local dev server port]
PortA -.->|no host-port collision| PortB
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Performance Report for
|
| Metric | Value |
|---|---|
| Total tests | 2936 |
| Total time | 131.29s |
| Mean | 0.0447s |
| Median | 0.0020s |
Top 10 slowest tests
| Test | Time (s) |
|---|---|
test.test_bench_examples.TestBenchExamples::test_example_meta |
16.544 |
test.test_split_render_examples::test_split_render_subprocess_media |
5.313 |
test.test_hash_persistent.TestCrossProcessDeterminism::test_hash_stable_across_two_processes[ResultBool] |
5.042 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_drift.py] |
3.665 |
test.test_over_time_save_perf::test_save_faster_without_aggregated_tab |
3.379 |
test.test_over_time_repeats.TestMaxSliderPoints::test_default_subsampling_caps_at_max |
2.631 |
test.test_render.TestCollect::test_collect_constructs_far_fewer_objects_than_render |
2.456 |
test.test_generated_examples::test_generated_example[cartesian_animation/example_cartesian_animation.py] |
2.430 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_noise.py] |
2.416 |
test.test_generated_examples::test_generated_example[result_types/result_image/example_result_image_to_video.py] |
2.323 |
Updated by Performance Tracking workflow
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.
|
Pushed a correction to this branch. The earlier commit removed the Nothing broke under The |
Performance Report for
|
| Metric | Value |
|---|---|
| Total tests | 2936 |
| Total time | 156.18s |
| Mean | 0.0532s |
| Median | 0.0020s |
Top 10 slowest tests
| Test | Time (s) |
|---|---|
test.test_bench_examples.TestBenchExamples::test_example_meta |
18.110 |
test.test_split_render_examples::test_split_render_subprocess_media |
6.361 |
test.test_hash_persistent.TestCrossProcessDeterminism::test_hash_stable_across_two_processes[ResultBool] |
6.132 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_drift.py] |
4.567 |
test.test_over_time_save_perf::test_save_faster_without_aggregated_tab |
4.486 |
test.test_generated_examples::test_generated_example[cartesian_animation/example_cartesian_animation.py] |
3.016 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_noise.py] |
2.970 |
test.test_generated_examples::test_generated_example[result_types/result_image/example_result_image_to_video.py] |
2.748 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_step.py] |
2.697 |
test.test_over_time_repeats.TestMaxSliderPoints::test_default_subsampling_caps_at_max |
2.482 |
Updated by Performance Tracking workflow
…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.
Performance Report for
|
| Metric | Value |
|---|---|
| Total tests | 2936 |
| Total time | 148.90s |
| Mean | 0.0507s |
| Median | 0.0020s |
Top 10 slowest tests
| Test | Time (s) |
|---|---|
test.test_bench_examples.TestBenchExamples::test_example_meta |
17.003 |
test.test_split_render_examples::test_split_render_subprocess_media |
6.151 |
test.test_hash_persistent.TestCrossProcessDeterminism::test_hash_stable_across_two_processes[ResultBool] |
6.085 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_drift.py] |
4.441 |
test.test_over_time_save_perf::test_save_faster_without_aggregated_tab |
4.001 |
test.test_generated_examples::test_generated_example[cartesian_animation/example_cartesian_animation.py] |
3.087 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_noise.py] |
2.868 |
test.test_over_time_repeats.TestMaxSliderPoints::test_default_subsampling_caps_at_max |
2.832 |
test.test_generated_examples::test_generated_example[result_types/result_image/example_result_image_to_video.py] |
2.669 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_step.py] |
2.484 |
Updated by Performance Tracking workflow
The prek job failed on two findings in the new script: - SC2020: `tr ' ,' '\n\n'` duplicates the replacement char. tr pads a short set2 out to set1's length on its own, so one `\n` does the same job. - SC2043: `for task in prek-install` loops over a literal single word, which shellcheck reads as bad quoting. The list is meant to grow per repo, so it is now an array and the loop expands it.
Performance Report for
|
| Metric | Value |
|---|---|
| Total tests | 2936 |
| Total time | 150.95s |
| Mean | 0.0514s |
| Median | 0.0020s |
Top 10 slowest tests
| Test | Time (s) |
|---|---|
test.test_bench_examples.TestBenchExamples::test_example_meta |
17.202 |
test.test_hash_persistent.TestCrossProcessDeterminism::test_hash_stable_across_two_processes[ResultBool] |
6.110 |
test.test_split_render_examples::test_split_render_subprocess_media |
6.065 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_drift.py] |
4.522 |
test.test_over_time_save_perf::test_save_faster_without_aggregated_tab |
4.063 |
test.test_generated_examples::test_generated_example[cartesian_animation/example_cartesian_animation.py] |
3.084 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_noise.py] |
2.857 |
test.test_generated_examples::test_generated_example[result_types/result_image/example_result_image_to_video.py] |
2.719 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_step.py] |
2.510 |
test.test_over_time_repeats.TestMaxSliderPoints::test_default_subsampling_caps_at_max |
2.356 |
Updated by Performance Tracking workflow
The PR claims this tree is byte-identical to python_template's apart from `name`, and it was not: this file's ~/.ssh comment had drifted to a shorter version that never mentions why post-create.sh runs ssh-keyscan. The template's wording -- auth from the forwarded agent, host identity from keyscan -- is the one that explains the script sitting next to it, and having the block match byte for byte is the whole point of moving `name` to the end of the file. With this the two files differ only in `name`.
Performance Report for
|
| Metric | Value |
|---|---|
| Total tests | 2936 |
| Total time | 156.10s |
| Mean | 0.0532s |
| Median | 0.0020s |
Top 10 slowest tests
| Test | Time (s) |
|---|---|
test.test_bench_examples.TestBenchExamples::test_example_meta |
18.163 |
test.test_split_render_examples::test_split_render_subprocess_media |
6.358 |
test.test_hash_persistent.TestCrossProcessDeterminism::test_hash_stable_across_two_processes[ResultBool] |
6.172 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_drift.py] |
4.619 |
test.test_over_time_save_perf::test_save_faster_without_aggregated_tab |
4.492 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_noise.py] |
3.067 |
test.test_generated_examples::test_generated_example[cartesian_animation/example_cartesian_animation.py] |
2.996 |
test.test_over_time_repeats.TestMaxSliderPoints::test_default_subsampling_caps_at_max |
2.992 |
test.test_generated_examples::test_generated_example[result_types/result_image/example_result_image_to_video.py] |
2.757 |
test.test_generated_examples::test_generated_example[regression/example_regression_tuning_step.py] |
2.712 |
Updated by Performance Tracking workflow
The devcontainer now pulls ghcr.io/blooop/python_template/devcontainer:latest
instead of building the image locally.
featuresblock is gone. The feature is baked intothat 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=hostis gone. A container per branch is the point ofdl, andhost networking undoes it: every port a dev server binds becomes a host port,
so two branches collide on the first one they share.
~/.sshand~/.config/ghmounts are gone.dlsupplies GH_TOKEN, andthe 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.
namemoved to the end of the file. It is the only per-repo line here, andsitting 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 published zero-build devcontainer image while simplifying branch isolation, credential handling, and repository initialization.
New Features:
Bug Fixes:
Enhancements:
CI:
Documentation:
Chores: