Skip to content

chore(devcontainer): default Claude to max effort and keep more state - #31

Open
amiralis1365 wants to merge 2 commits into
mainfrom
feat/devcontainer-baseline
Open

amiralis1365 wants to merge 2 commits into
mainfrom
feat/devcontainer-baseline

Conversation

@amiralis1365

@amiralis1365 amiralis1365 commented Oct 22, 2026 •

Copy link
Copy Markdown

Closes #30.

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:ubuntu floats, and it now resolves to Ubuntu 26.04 "resolute", where the docker-in-docker Feature (2.17.0) refuses its default moby option: the build stopped in that Feature, on main too, before any lifecycle script ran.

  • Claude Code starts every session at max effort. containerEnv sets CLAUDE_CODE_EFFORT_LEVEL=max, because the settings file's effortLevel accepts only low to xhigh and quietly drops max. The variable outranks /effort, so start a lighter session as CLAUDE_CODE_EFFORT_LEVEL=auto claude.

  • .claude.json survives a rebuild. CLAUDE_CONFIG_DIR=/home/vscode/.claude keeps it in the claude-config volume, beside the credentials and the /resume transcripts. 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_history points zsh and bash there, and containerEnv points the REPLs there.
    • cache: ~/.cache, where containerEnv already sends uv, pip, npm, bun, Go, Deno, ruff and mypy, so post-create's uv sync no longer starts from an empty cache on each rebuild.

    base_setup_config_dirs and base_setup_cache_dirs take ownership of both before anything writes to them.

  • gh logs in by itself, and git pushes through it (.devcontainer/scripts/lib/github-auth.sh):

    • post-create calls github_auth_seed through a new base_setup_github_seed, right after the ownership steps. It stores a token from the host's exported GH_TOKEN (MUSHER_HOST_GH_TOKEN) and writes no git config.
    • A new post-attach.sh calls ensure_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 .gitconfig brought for the host's own gh, and runs gh auth setup-git. This waits for an attach because VS Code copies the host's ~/.gitconfig only after post-create, and only into a container that has none: a file written earlier would cost you your name and email.
  • The ShellCheck job scans all of .devcontainer. It scanned .devcontainer/scripts, which left out config/shell/aliases.shared.sh, the file zsh sources on every start. Its change filter now covers that directory too.

  • Also: the Claude Code VS Code extension. The commented-out dind-data mount 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.sh is 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 sibling npm-registry.sh isn't copied, because nothing here installs from GitHub Packages. Type chore: nothing the package ships changes, so release-please cuts no release.

What a rebuild keeps

Volume (musher-${devcontainerId}-…) Mounted at Keeps
gh-config ~/.config/gh The gh login
claude-config ~/.claude Claude Code's login, settings and sessions (/resume), and now .claude.json
codex-config ~/.codex Codex's login and settings
shell-history (new) ~/.shell-history zsh, bash, Node, Python and psql history
cache (new) ~/.cache The uv, pip, npm, bun, Go and Deno download caches, and ruff's and mypy's

The compose stack's data, Postgres included, was already kept by the docker-in-docker Feature's own dind-var-lib-docker-${devcontainerId} volume. .venv/ and the examples' dependencies stay where they were, in your checkout on the bind mount. Claude Code, under ~/.local, and the global npm packages Codex and lefthook are still not kept; post-create installs them again.

Before and after your first rebuild

  • With the pin, a rebuild works again, on Ubuntu 24.04.
  • No volume is renamed, so there is nothing to copy. The two new volumes start empty, so this rebuild is the last one that loses your shell history and the caches.
  • .claude.json used 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.
  • The first attach seeds gh and wires git. If your host's credential lacks the repo and read:org scopes, as some credential managers' tokens do, run gh auth login once. The gh-config volume keeps it.

Test plan

  • devcontainer read-configuration (CLI 0.89.0): parses. The merged mounts are the five musher-${devcontainerId}-… volumes plus the docker-in-docker Feature's dind-var-lib-docker-${devcontainerId}. postAttachCommand, MUSHER_HOST_GH_TOKEN and the five new containerEnv keys are there, and waitFor is unchanged.
  • shellcheck -x --source-path=SCRIPTDIR over all 8 .devcontainer shell files: clean. The CI job's widened scan (scandir: .devcontainer, severity warning) picks up the same 8 files, and they pass it too. actionlint on validate.yaml: clean.
  • The pin: a plain devcontainer build of a clean main checkout (a6d577b) 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."
  • task check:lint and task check:format-check (ruff), and docker compose -f .devcontainer/compose.yaml config --quiet: clean, as on main.
  • github-auth.sh is byte-identical to the canonical copy at musher-dev/development-container@c12a6ba, and post-attach.sh is the template's.
  • With a scratch HOME, gh config and XDG_CONFIG_HOME, and no token:
    • base_setup_shell_history, run twice, leaves the marker and one line in each rc file. bash and zsh then read HISTFILE from ~/.shell-history, unexported.
    • github_auth_seed and post-attach.sh exit 0 with the non-fatal "no GitHub credential reached the container yet" line, and neither writes ~/.gitconfig. With GH_TOKEN set, the seed leaves gh to read it.
  • devcontainer build and up with fresh volumes and no GH_TOKEN (CLI 0.89.0), on this branch's config. The run used a copy pinned to base:ubuntu-24.04 before the pin commit existed, identical to the committed file apart from the comment above the image line:
    • post-create ran the ownership step for ~/.shell-history and the cache dirs, and logged the non-fatal line and both history lines.
    • It then stopped in a step this PR leaves alone. downloads.claude.ai answered the Claude Code installer with 403 from this network throughout the run, though the same download had worked in another repository's run 15 minutes earlier, and this repository's installer does not retry.
    • post-attach.sh, run by hand as an attach would run it, exited 0 with the same non-fatal line.
    • The container then showed CLAUDE_CODE_EFFORT_LEVEL=max; every mount, ~/.config and ~/.local owned by vscode; one marker and one line in each rc file; HISTFILE from ~/.shell-history in interactive zsh and bash; ensure_github_auth resolving; and no ~/.gitconfig. Cleanup removed the container and its six volumes.
    • up did not reach the rest of post-create (Codex, lefthook, base_verify_tools, the shell customization block and uv sync), postStart (the compose stack) or post-attach, which ran by hand instead. musher-dev/musher-cli's run of the same additions reached all of them.
  • The commit passed the repo's pre-commit hook (lefthook; its ruff jobs had no Python files to check).
  • CI green: all 5 checks pass, and Compose Config is skipped because no compose file changed. Devcontainer Build (devcontainers/ci@v0.3) built the pinned base:ubuntu-24.04 image and ran devcontainer up through the whole lifecycle. post-create logged the ownership step, the non-fatal "no GitHub credential reached the container yet" line and both history lines, installed Claude Code 2.1.307, passed base_verify_tools, ran uv sync and finished. postStart ran, and post-attach ran and logged the same non-fatal line. So CI reached the steps the local run above could not.
  • A rebuild of an existing container: git identity kept, gh green, /resume lists earlier sessions, history survives.

🤖 Generated with Claude Code

amiralis1365 and others added 2 commits October 21, 2026 22:47
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 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.

The ShellCheck job scans all of .devcontainer now, because the aliases file
under config/shell sat outside its scan.

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 branch has not been deployed

No deployments
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.

Dev container: fix the build, start Claude at max effort, seed gh, and keep history and caches across rebuilds

1 participant