fix(claude): bump adapter + claude-code to unblock Opus 4.7 in upstream image#474
Merged
thepagent merged 1 commit intoopenabdev:mainfrom Apr 19, 2026
Merged
Conversation
Before this change, `openab-claude:0.7.8-beta.7` ships: - claude-agent-acp@0.25.0 — hardcoded model list, no Opus 4.7 - claude-code@2.1.104 — knows up to Opus 4.6 only - ENV CLAUDE_CODE_EXECUTABLE=/usr/local/bin/claude (openabdev#447) With openabdev#447 making the pinned claude-code binary load-bearing, neither the adapter's availableModels nor the CLI's model resolver knows about Opus 4.7 — users get Sonnet 4.6 regardless of ANTHROPIC_MODEL=opus. This PR: - introduces `CLAUDE_AGENT_ACP_VERSION` ARG (pattern parity with `CLAUDE_CODE_VERSION` from openabdev#326/openabdev#412) - bumps adapter 0.25.0 → 0.29.2 (brings claude-agent-sdk 0.2.111+ whose availableModels includes Opus 4.7) - bumps claude-code 2.1.104 → 2.1.114 anthropics/claude-code#49512 (parallel-mkdir ENOENT race) was filed against 2.1.112 and is still OPEN but has zero comments. Inspection of the 2.1.114 install shows the CLI moved to a per-platform native binary (openabdev#2.1.113) and session state relocated from `/tmp/claude-<uid>/…/tasks/` to `$HOME/.claude/{projects,tasks}/`, so the vulnerable filesystem layout no longer exists — binary-grep for `/home-//tasks` returns 0 matches. 50 parallel `claude -p` calls as the same user (40ms stagger) produced 0/50 errors, 0 bytes stderr, and no `/tmp/claude-*` directories. Refs openabdev#326, openabdev#412, openabdev#418, openabdev#447 Closes nothing explicitly (no issue filed; repro + rationale in body). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
thepagent
approved these changes
Apr 19, 2026
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.
What problem does this solve?
After #447 (
0.7.8-beta.5) setENV CLAUDE_CODE_EXECUTABLE=/usr/local/bin/claude, the adapter now runs the pinned@anthropic-ai/claude-codebinary instead of its own bundled SDKcli.js. That fix was correct, but the versions pinned in the Dockerfile never learned about Opus 4.7:claude-agent-acp@0.25.0— hardcodedavailableModelslist tops out at Sonnet 4.6 / Haiku 4.5claude-code@2.1.104— model resolver knows up toclaude-opus-4-6Net result with the current image (
ghcr.io/openabdev/openab-claude:0.7.8-beta.7):Users who want Opus 4.7 today either have to build the image locally with a newer adapter + CLI, or set
CLAUDE_CODE_EXECUTABLE=""to get the adapter to use its own bundled cli.js — defeating #447's pinning semantics.Closes #
Refs #326, #412, #418, #447
Discord Discussion URL: https://discord.com/channels/1491295327620169908/1491564498492850217/1495445157640929444
At a Glance
Both layers need to understand 4.7 for the end-to-end flow to work. Bumping only the adapter leaves the runtime CLI unable to route the model; bumping only the CLI leaves the availableModels list missing the option.
Prior Art & Industry Research
scripts/test-live-acp-bind-docker.sh) binds an ACP layer directly toclaude-cli/codex-cli/gemini-cliwithout a separate JS adapter, so there is no equivalent "npm adapter version" to pin. The two-layer pinning problem is unique to openab's architecture.skills/coding-agent/SKILL.md) invokes Claude through a skill definition, not a long-running adapter subprocess. Again no direct analogue.CLAUDE_CODE_VERSION(fix: pin CLI versions in all Dockerfiles using ARG for reproducible builds #326 added)CODEX_VERSION/GEMINI_CLI_VERSION/COPILOT_VERSION/CURSOR_VERSION(fix: bump CLI versions — codex 0.121.0, gemini 0.38.1, copilot 1.0.30, cursor 2026.04.15 #412)KIRO_CLI_VERSION(fix: pin CLI versions in all Dockerfiles using ARG for reproducible builds #326)claude-agent-acp,codex-acp) are still hardcoded string literals — this PR extends the pattern toCLAUDE_AGENT_ACP_VERSION. (A follow-up could do the same forcodex-acpinDockerfile.codex; out of scope here to keep the review tight.)Proposed Solution
Paired bumps:
@agentclientprotocol/claude-agent-acp0.25.0 → 0.29.2— spans four minor releases that include:0.26.0bundled sdk 0.2.96, TUI login for remote envs0.27.0bundled sdk 0.2.104, raw-SDK message opt-in0.28.0bundled sdk 0.2.1090.29.0bundled sdk 0.2.111 → adds Opus 4.7 (release note)0.29.1,0.29.2— minor follow-ups on 0.29.0@anthropic-ai/claude-code2.1.104 → 2.1.114— brings the model resolver table forward soopusalias maps toclaude-opus-4-7.Why this approach
ENV CLAUDE_CODE_EXECUTABLEwould give the adapter its bundled cli.js (which knows 4.7) but undo the observability/reproducibility win of fix: wire CLAUDE_CODE_EXECUTABLE so adapter uses pinned claude-code #447.--build-arg.docker build --build-arg CLAUDE_AGENT_ACP_VERSION=0.25.0 --build-arg CLAUDE_CODE_VERSION=2.1.104 ...pins back to today's exact image.claude-code@2.1.113dropped the bundled JavaScript CLI in favor of a per-platform pre-compiled binary (bin/claude.exe) and moved per-session state from/tmp/claude-<uid>/…/tasks/to$HOME/.claude/{projects,tasks}/. The vulnerable filesystem layout behind anthropics/claude-code#49512 no longer exists in 2.1.114 (grep evidence in the risk section below). That removes the main reason fix: bump CLI versions — codex 0.121.0, gemini 0.38.1, copilot 1.0.30, cursor 2026.04.15 #412 held back; we are landing on 2.1.114 after the architectural shift, not on 2.1.112 where the race was first reported.Alternatives Considered
CLAUDE_CODE_VERSION=2.1.104opusalias still maps to 4-6 at runtime; ACP session would reportcurrentModelId=opusbut the actual API call would use the older ID. Confusing partial fix.ENV CLAUDE_CODE_EXECUTABLEclaude-code@2.1.111instead of 2.1.114settings.jsonmodel preference silently ignored. Worse than #49512 for our case because it affectsANTHROPIC_MODELrouting (the very thing we're trying to wire up).claude-code@2.1.110Known risk assessment:
anthropics/claude-code#49512— empirically not reproducible in 2.1.114The referenced upstream issue was filed 2026-04-16 against
claude-code@2.1.112and reports anENOENTrace onmkdir '/tmp/claude-<uid>/-home-//tasks'when parallel sessions run as the same user on Linux. The issue is still OPEN but has had zero comments since filing and no upstream fix commit.Why we believe it's already fixed incidentally:
claude-code@2.1.113changed the CLI to "spawn a native Claude Code binary (via a per-platform optional dependency) instead of bundled JavaScript" (release notes). This rewrote the session-state layout. In 2.1.114 the/tmp/claude-<uid>/...tree no longer exists — session state lives entirely under$HOME/.claude/. The exact path that triggered #49512'sENOENTis gone.Code-level evidence from the 2.1.114 install:
i.e. there is no more bundled
cli.js;/usr/local/bin/clauderesolves to a pre-compiledbin/claude.exe(236 MB native binary). Binary-grep on that executable:Since each OS user gets a single
$HOME/.claude/tasks/namespace (rather than shared/tmp/claude-<uid>/with sibling cleanup races), concurrent sessions as the same user no longer step on each other's directory lifecycles. The race's necessary precondition — overlapping mkdir/rmdir in a shared/tmplocation — has been structurally removed.Empirical verification (run 2026-04-19 against the proposed image):
The previously-vulnerable
/tmp/claude-<uid>/-home-//tasks/path is not used by 2.1.114. We consider #49512 effectively fixed by the 2.1.113 architecture change, even though the upstream issue is not yet formally closed.Fallback plan if the race does surface in production: users can pin back with
--build-arg CLAUDE_CODE_VERSION=2.1.110(loses Opus 4.7 routing, returns to 4.6) while we file a new upstream issue with the new repro.Validation
Build:
docker build -f Dockerfile.claude -t openab-claude:test --build-arg CLAUDE_AGENT_ACP_VERSION=0.29.2 --build-arg CLAUDE_CODE_VERSION=2.1.114 .— cleanPinned versions baked in:
docker run --rm --entrypoint sh openab-claude:test -c 'claude --version && npm ls -g @agentclientprotocol/claude-agent-acp':ACP exposes Opus 4.7: adapter 0.29.2's
availableModelsnow contains:{"modelId":"opus","name":"Opus","description":"Opus 4.7 · Most capable for complex work"}and with
ANTHROPIC_MODEL=opus,currentModelId=opus.CLI actually routes to Opus 4.7 — verified in two forms:
Full model ID (
--model claude-opus-4-7):{"type":"result","subtype":"success","is_error":false,"result":"ok", "total_cost_usd":0.05067125, "modelUsage":{"claude-opus-4-7":{"inputTokens":6,"outputTokens":6, "contextWindow":200000,"maxOutputTokens":64000,"costUSD":0.05067125}}}Alias (
--model opus) resolves to the same model:{"type":"result","subtype":"success","result":"ok", "modelUsage":{"claude-opus-4-7":{"inputTokens":6,"outputTokens":6, "contextWindow":200000,"maxOutputTokens":64000,"costUSD":0.05054625}}}Cost (~$0.05/call) is consistent with Opus 4.7 pricing. Pre-bump, the same alias resolved to
claude-opus-4-6(see issue referenced above).Backward-compat override:
--build-arg CLAUDE_AGENT_ACP_VERSION=0.25.0 --build-arg CLAUDE_CODE_VERSION=2.1.104still builds and reproduces today's pre-bump behaviour.#49512 stress test — 20 parallel
claude -psessions, 50ms stagger: 20/20 exit 0, zero stderr, no ENOENT, no/tmp/claude-*directories created.#49512 aggressive stress — 50 parallel sessions, mixed short/long prompts, 40ms stagger (~2s spawn window): 50/50 exit 0, 50/50 valid API response, 0 bytes total stderr, zero ENOENT / mkdir / panic traces (see "Known risk assessment" above for the full command + output).
cargo check --all-targetsclean (no Rust changes, sanity run from main).cargo testpasses (no Rust changes, sanity run from main).helm unittest charts/openabpasses (no chart changes).