Repository navigation
chore(devcontainer): default Claude to max effort and keep more state - #108
Open
amiralis1365 wants to merge 2 commits into
Open
amiralis1365 wants to merge 2 commits into
amiralis1365 wants to merge 2 commits into
Conversation
Claude Code's settings file has no "max" effort, so CLAUDE_CODE_EFFORT_LEVEL is the only way to start every session there. It outranks /effort, and `CLAUDE_CODE_EFFORT_LEVEL=auto claude` opts one session out. Without CLAUDE_CONFIG_DIR, Claude writes .claude.json to ~/, outside its volume, so every rebuild lost the account and onboarding state. Two new volumes keep shell and REPL history and the download caches, Go's modules and builds among them, across a rebuild as well; post-create takes ownership of both before anything writes to them. post-create now seeds gh from the host's exported GH_TOKEN, and a new post-attach hook wires git to it. Not earlier: VS Code copies the host's ~/.gitconfig only after post-create, and only when none exists, so a file written first would cost the developer their identity. github-auth.sh is a verbatim copy of the canonical file in musher-dev/development-container. shfmt leaves that copy as it is (.editorconfig, `--apply-ignore`), because its formatting is the canonical file's; ShellCheck still scans it. Claude Code comes from its native installer, as in the SDK repositories, instead of the claude-code Feature's npm install. The pipeline runs under pipefail, so a failed download is retried: without it bash runs the empty script, exits 0, and retry never sees the failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
base:ubuntu now resolves to Ubuntu 26.04 "resolute", where the docker-in-docker Feature refuses its default moby option, so the dev container no longer builds, on main as well. ubuntu-24.04 is the template's image and the release these containers ran before the tag moved. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #107.
Summary
The dev container builds again. A separate commit pins the base image to
mcr.microsoft.com/devcontainers/base:ubuntu-24.04, the template's image.base:ubuntufloats, and it now resolves to Ubuntu 26.04 "resolute", where the docker-in-docker Feature (2.17.0) refuses its defaultmobyoption: the build stopped in that Feature, onmaintoo, before any lifecycle script ran.Claude Code starts every session at max effort.
containerEnvsetsCLAUDE_CODE_EFFORT_LEVEL=max, because the settings file'seffortLevelaccepts onlylowtoxhighand quietly dropsmax. The variable outranks/effort, so start a lighter session asCLAUDE_CODE_EFFORT_LEVEL=auto claude..claude.jsonsurvives a rebuild.CLAUDE_CONFIG_DIR=/home/vscode/.claudekeeps it in theclaude-configvolume, beside the credentials and the/resumetranscripts. Until now it landed in~/and was lost.A rebuild keeps more. Two new
musher-${devcontainerId}-<purpose>volumes join the gh, Claude and Codex ones:shell-history: zsh, bash, Node, Python and psql history.base_setup_shell_historypoints zsh and bash there, andcontainerEnvpoints the REPLs there.cache:~/.cache, wherecontainerEnvalready sends Go's module and build caches, uv, pip, npm, bun, Deno, ruff and mypy. post-create'stask setupno longer starts from an empty Go module and build cache on each rebuild.base_setup_config_dirsandbase_setup_cache_dirstake ownership of both before anything writes to them.gh logs in by itself, and git pushes through it (
.devcontainer/scripts/lib/github-auth.sh):github_auth_seedthrough a newbase_setup_github_seed, right after the ownership steps. It stores a token from the host's exportedGH_TOKEN(MUSHER_HOST_GH_TOKEN) and writes no git config.post-attach.shcallsensure_github_auth. If gh still has no token, it asks VS Code's forwarded credential helper. Then it clears the helper lines the host's.gitconfigbrought for the host's own gh, and runsgh auth setup-git. This waits for an attach because VS Code copies the host's~/.gitconfigonly after post-create, and only into a container that has none: a file written earlier would cost you your name and email.Claude Code comes from its native installer, which updates itself, instead of the
claude-codeFeature's npm install.base_install_claude_codeis typescript-sdk's, with one fix: the pipeline runs underpipefail. Without it, a failed download hands bash an empty script, bash exits 0, and the three retries never happen. A failed install still fails post-create, as a failed Feature failed the build, andbase_verify_toolsstill checksclaude.shfmt leaves the shared script alone.
task check:shellrunsshfmt -d -i 2 -ci -srover every*.sh, and those flags would reformatgithub-auth.sh, which must stay byte-identical to the canonical copy. An.editorconfigsection marks itignore = true, and the three shfmt calls inTaskfile.yml(check:shell,check:shell:files, which the pre-commit hook runs, andfmt) pass--apply-ignore. ShellCheck still scans it.Also: the Claude Code VS Code extension. The commented-out
dind-datamount gives way to a note: the docker-in-docker Feature already keeps/var/lib/docker, where the compose services' data lives, on a volume of its own.github-auth.shis a verbatim copy of the canonical script in musher-dev/development-container#55; musher-dev/platform-backstage#114 was the first repository to copy it. Its siblingnpm-registry.shisn't copied, because nothing here installs from GitHub Packages. Typechore: the CLI doesn't change, so release-please cuts no release.What a rebuild keeps
musher-${devcontainerId}-…)gh-config~/.config/ghghloginclaude-config~/.claude/resume), and now.claude.jsoncodex-config~/.codexshell-history(new)~/.shell-historycache(new)~/.cacheThe compose stack's data, Postgres included, was already kept by the docker-in-docker Feature's own
dind-var-lib-docker-${devcontainerId}volume. The git hooks stay where they were, in your checkout on the bind mount. The Go toolstask setupinstalls into/go/bin, Claude Code under~/.local, and Codex are still not kept; post-create installs them again.Before and after your first rebuild
.claude.jsonused to live outside the volume, so Claude Code may run its first-run steps once more after this rebuild. It keeps them from then on.~/.local/bin/claude. Your login, settings and sessions stay in~/.claude.repoandread:orgscopes, as some credential managers' tokens do, rungh auth loginonce. Thegh-configvolume keeps it.Test plan
devcontainer read-configuration(CLI 0.89.0): parses. The merged mounts are the fivemusher-${devcontainerId}-…volumes plus the docker-in-docker Feature'sdind-var-lib-docker-${devcontainerId}, and noclaude-codeFeature remains.postAttachCommand,MUSHER_HOST_GH_TOKENand the five newcontainerEnvkeys are there, andwaitForis unchanged.shellcheck -x --source-path=SCRIPTDIRover all 8.devcontainershell files: clean.devcontainer buildof a cleanmaincheckout (1974505) stops in the docker-in-docker Feature with "(!) The 'moby' option is not supported on ubuntu 'resolute' because 'moby-cli' and related system packages are not available in that distribution." So did this branch before the pin commit.task check:shell,task check:repo-policyandtask check:workfloware clean, as onmain. Without the exemption,shfmt -d -i 2 -ci -srrewritesgithub-auth.sh; with--apply-ignoreit skips that one file and still reports the others.github-auth.shis byte-identical to the canonical copy at musher-dev/development-container@c12a6ba.post-attach.shis the template's, with this repository's root-relative# shellcheck source=path.devcontainer buildandupwith fresh volumes and noGH_TOKEN(CLI 0.89.0), on this branch's config. The run used a copy pinned tobase:ubuntu-24.04before the pin commit existed, identical to the committed file apart from the comment above the image line:~/.shell-historyand the cache dirs, the non-fatal "no GitHub credential reached the container yet" line and both history lines. It then installed Claude Code 2.1.307 natively (no npm package left), passedbase_verify_tools, and rantask setup, which installed the hooks. postStart brought Postgres up healthy, and post-attach ran and logged the same non-fatal line.CLAUDE_CODE_EFFORT_LEVELismax. Every mount, and~/.config,~/.localand~/.local/bin, is owned byvscode. Each rc file has one marker and one line, and interactive zsh and bash readHISTFILEfrom~/.shell-history.ensure_github_authresolves, and there is no~/.gitconfig.pipefailline, which changes only what a failed download does; the retry test above covers that.task check:ci:lint): on this branch, every step up tocheck:lintpasses,check:shellincluded (the image has norg, socheck:repo-policychecks nothing there; the host run above covers it).check:lintthen fails onmainexactly as here, because the Go Feature installs the newest Go, 1.27.3, which golangci-lint 2.11.3 cannot typecheck against. CI takes Go fromgo.mod(1.26.5).shell: shfmt and ShellCheck on the four staged scripts) and its commit-msg hook.task check:pre-push): the policy test, golangci-lint 2.11.3 with no issues, andgo test -v -race ./...with every package passing, on Go 1.26.5, thego.modversion.check:vuln, on 20 called vulnerabilities thatmainhas too: Go 1.26.5's standard library (fixed in 1.26.6, 1.26.9 and 1.26.10) and the grpc and otel exporter versions ingo.sum. 19 of the 20 advisories were published aftermain's last green run on 2026-08-05, and the 20th, GO-2026-5026, gained its standard-library range on 2026-10-16 (OSV). This PR changes no Go file,go.modorgo.sum. The two Smoke jobs need Test, so they were skipped. The tests Test runs aftercheck:vulnpassed in the pre-push hook above. No job builds the dev container./resumelists earlier sessions, history survives.🤖 Generated with Claude Code