Skip to content

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

Merged
amiralis1365 merged 1 commit into
mainfrom
feat/devcontainer-baseline
Oct 22, 2026
Merged

amiralis1365 merged 1 commit into
mainfrom
feat/devcontainer-baseline

Conversation

@amiralis1365

@amiralis1365 amiralis1365 commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #195.

Summary

  • 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 volumes in the DEVC-08 form join the gh, Claude and Codex ones: musher-${devcontainerId}-shell-history (zsh and bash history, which base_setup_shell_history points there, and Node's REPL history, through NODE_REPL_HISTORY) and -cache (~/.cache, where containerEnv already sends bun and npm). Both are in base_setup_config_dirs/base_setup_cache_dirs, which take ownership before anything writes.
  • 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 when it attaches, and only into a container that has none: a file written earlier would cost you your name and email.
  • Also: the Claude Code VS Code extension. Codex stays opt-in (MUSHER_INSTALL_CODEX=1 in .devcontainer/.env); its pin and its volume were already here.

github-auth.sh is a verbatim copy of the canonical script in musher-dev/development-container#55. The first repository to use it is musher-dev/platform-backstage#114. Type chore: nothing under specifications/ changes, so no family is released.

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, once you opt in
shell-history (new) ~/.shell-history zsh, bash and Node REPL history
cache (new) ~/.cache The bun and npm download caches containerEnv points there, and every other tool's XDG cache, mise's and Claude Code's among them

tools/node_modules/, dist/ and the git hooks stay where they were, in your checkout on the bind mount.

Before and after your first rebuild

  • 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 download 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 --include-merged-configuration (CLI 0.89.0): parses, and the merged mounts are the five volumes, no Feature adding one.
  • shellcheck -x --source-path=SCRIPTDIR over all 9 .devcontainer scripts: clean. task check:shell and CI's ShellCheck job (scandir: .devcontainer/scripts) already cover both new files.
  • task lint (format, config, rulesets, commits, docs, links, ADRs, markdown, spelling, shell, workflows): clean, as on main.
  • conventions check --fail-on warning at the pinned 0.7.0: no findings, as on main.
  • task check, which the pre-push hook runs: passed.
  • The commit passed the repo's pre-commit (ShellCheck on the staged scripts) and commit-msg hooks, and its Signed-off-by matches its author.
  • devcontainer build --frozen-lockfile: succeeds. No Feature changed, so devcontainer-lock.json is untouched. CI's Feature Lockfile job runs the same build but no lifecycle hook, so the next item ran locally.
  • Fresh-volume devcontainer up, with no GH_TOKEN or GITHUB_TOKEN passed in:
    • initializeCommand, post-create, post-start and post-attach all ran, and post-create verified every tool it installs. Create and attach each logged the non-fatal "no GitHub credential reached the container yet" line.
    • CLAUDE_CODE_EFFORT_LEVEL=max, CLAUDE_CONFIG_DIR=/home/vscode/.claude, and NODE_REPL_HISTORY points at the volume. The image's Python is 3.12.3, which reads no PYTHON_HISTORY, and it has no psql, so neither variable is set.
    • The five volumes, ~/.config and ~/.local are owned by vscode. ~/.config already exists in the image, so no mount makes Docker create a root-owned parent.
    • Claude Code 2.1.306 wrote its .claude.json inside the volume, at ~/.claude/.claude.json; there is no ~/.claude.json.
    • One history line at the end of each rc file, and still one after the step runs again. Interactive zsh and bash under a pty use ~/.shell-history.
    • No ~/.gitconfig after create and attach.
    • A MUSHER_HOST_GH_TOKEN that GitHub refuses is logged and skipped, and the seed still exits 0. A second post-attach.sh exits 0.
    • gh 2.96.0, task 3.52.0, bun 1.3.14, node 24.18.0, lefthook 2.1.10 and conventions 0.7.0 are installed. Codex is not, because MUSHER_INSTALL_CODEX is unset. task bundle built dist/. bun install had nothing to do, because the clone's tools/node_modules already existed.
  • CI green: all 13 jobs pass, ShellCheck, Feature Lockfile and Commits / Sign-off included. Record pending release skips, because it runs only on release-please branches.
  • A rebuild of an existing container: git identity kept, gh green, /resume lists earlier sessions, history survives.

🤖 Generated with Claude Code

Claude Code's settings file accepts an effortLevel of low to xhigh and
drops "max", so only CLAUDE_CODE_EFFORT_LEVEL can make max the default.
It outranks /effort too; `CLAUDE_CODE_EFFORT_LEVEL=auto claude` opts a
session out.

CLAUDE_CONFIG_DIR keeps .claude.json in the claude-config volume. It
landed in ~/ instead, so every rebuild lost the account and onboarding
state.

Two new volumes keep shell history and ~/.cache, where containerEnv
already sends bun and npm. post-create takes ownership of both before
anything writes, and appends one HISTFILE line to each rc file;
NODE_REPL_HISTORY joins them on the volume. The image's Python is 3.12,
which reads no PYTHON_HISTORY, and it has no psql, so neither is set.

gh had a volume, but nothing ever logged it in. post-create now seeds
it from the host's exported GH_TOKEN and writes no git config, because
VS Code copies the host's ~/.gitconfig only into a container that has
none. A new post-attach hook asks VS Code's forwarded credential helper
when gh still has no token, then points git's github.com credential at
gh. lib/github-auth.sh is a verbatim copy of the canonical script in
musher-dev/development-container.

Also adds the Claude Code VS Code extension. Codex stays opt-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Ali <amirali.sadrzadeh@gmail.com>
@amiralis1365
amiralis1365 merged commit 4d0db3c into main Oct 22, 2026
18 checks passed
@amiralis1365
amiralis1365 deleted the feat/devcontainer-baseline branch October 22, 2026 16:15
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: start Claude at max effort, seed gh, and keep history and caches across rebuilds

1 participant