Dockerfile: pin claude-code version explicitly, don't inherit "latest at build time" #83
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks#83
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As the operator, I want the agent container's
claude-codebinary pinned to a specific version number in the Dockerfile, so
that an upstream regression never silently lands in our agents the
next time we rebuild the image.
What happened (concrete)
Claude Code
v2.1.111introduced a ~14% context-window bloatregression (anthropics/claude-code#49593).
Our containers currently ship
v2.1.112because the Dockerfiledoes
npm install -g @anthropic-ai/claude-codewith no versionpin — it picks up whatever's latest at image build time. We
inherited the regression without a decision or a PR.
The host operator's
claudeis onv2.1.113, so interactivesessions also carry the bloat. But the cost concentrates on the
SDK caller:
claude-hooksagents' first turn already hits the200k budget thanks to MCP tool schemas (see #81 for details), so
an extra ~14% from the regression tips us over the limit.
Observed on task
695b934e-6db9-4b35-990c-924b8b39e717on #79:boss died turn 1 with
Prompt is too long.Why "always latest" is the wrong default here
For interactive operator use, auto-updating is fine — the
operator can roll back, pin, or route around issues. For
webhook-dispatched agents the failure mode is:
claude-code.A pinned version trades convenience for reproducibility. We
already do this for
forgejo-mcp(baked in at a specific upstreamtag plus patches);
claude-codeshould follow the same pattern.Acceptance criteria
Pin & bump mechanics
Dockerfilepinsclaude-codeto a known-good version vianpm install -g @anthropic-ai/claude-code@X.Y.Z— initialpin = the latest version before 2.1.111's bloat, i.e.
2.1.110.
ARG CLAUDE_CODE_VERSION=2.1.110at the top of theDockerfile, referenced in the
npm installstep — sobumping is one line.
explaining why we pin (+ the v2.1.111 regression that
motivated it).
Visibility
scripts/smoke-creds.shasserts the container'sclaude --versionmatches the pinned value. Fails loud ifa local rebuild drifted.
GET /health) includesclaude_code_versionper container (runclaude --versionon startup and cache).
Bump cadence
CLAUDE.md:claude-codeversion bumps areintentional PRs that (a) bump the
ARG, (b) rebuild theimage, (c) run the full smoke suite (
scripts/smoke-creds.sh+ re-dispatch #62 / #77 / #79 as a post-merge gate) before
merge.
Out of scope
@anthropic-ai/claude-agent-sdk) —already pinned in
package.json. Only the CLI bundled into theagent container is the unpinned surface.
that human-gated bumps are fine.
References
2.1.111 context bloat regression.
contributor to the prompt-size problem.
Dockerfile— where the pin lands.Dependencies
main./cancelendpoint: accept anagentparam instead of cancelling the first busy worker #87