ci(docker): build multi-arch images (amd64 + arm64)#3392
Merged
Conversation
The agent images at ghcr.io/openrouterteam/spawn-<agent>:latest were built linux/amd64 only. On Apple Silicon (arm64) hosts running --beta sandbox, OrbStack pulls the amd64 image and runs it under Rosetta. Inside the container, github-auth.sh's `apt-get update` to install gh hangs in emulation — confirmed by `[rosetta] /usr/lib/apt/methods/http` processes sleeping forever. A native arm64 ubuntu:24.04 finishes the same apt-get update + curl install in ~12s; the amd64-emulated run was still stuck after 5+ minutes. Adds docker/setup-qemu-action + docker/setup-buildx-action and sets platforms: linux/amd64,linux/arm64 on the build-push step. Builds will take longer (arm64 layer compiles under QEMU on the amd64 runner), but the resulting multi-arch manifest gives Apple Silicon users native arm64 binaries and unblocks the sandbox flow. All current Dockerfiles (claude, codex, cursor, hermes, junie, kilocode, openclaw, opencode, pi) install via npm or arch-aware curl scripts, so they're already arch-portable.
Post-build step runs `docker buildx imagetools inspect` and greps the manifest for both linux/amd64 and linux/arm64. Catches regressions where setup-qemu/buildx gets dropped or the `platforms:` flag gets lost in a future refactor — silent single-arch publishes would be invisible until an Apple Silicon user hit the Rosetta hang again. One post-build step per matrix entry keeps the check local to the agent that was just pushed.
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.
Summary
docker/setup-qemu-action+docker/setup-buildx-actionto.github/workflows/docker.yml, and setsplatforms: linux/amd64,linux/arm64on the build-push step.--beta sandboxwill now pull a native arm64 image instead of falling back to Rosetta emulation of amd64.Why
spawn <agent> local --beta sandboxhangs at the GitHub auth step on M-series Macs. Inside the running container I caught the smoking gun:github-auth.shtriggersapt-get updateto installgh. Under Rosetta x86_64 emulation on arm64, the apt http methods sleep indefinitely.Side-by-side reproduction (host:
arm64, OrbStack):ubuntu:24.04 linux/arm64(native)ubuntu:24.04 linux/amd64(Rosetta)When the user passes
SPAWN_SKIP_GITHUB_AUTH=1(or has no local gh token), no apt-get runs at runtime and the sandbox boots fine — confirming the hang is the apt path under emulation.Compatibility
All current Dockerfiles (
claude,codex,cursor,hermes,junie,kilocode,openclaw,opencode,pi) install vianpm install -g,curl ... | bash, oruname -m-aware download. None depend on amd64-only artifacts, so multi-arch builds should succeed unchanged.QEMU-emulated arm64 builds add CI time (Node install, npm global, curl-based installers run under emulation on the amd64 GH runner). The schedule is daily, so the extra few minutes per agent is acceptable.
Test plan
workflow_dispatch) and verify eachspawn-<agent>:latestis published as a multi-arch manifest (docker manifest inspect ghcr.io/openrouterteam/spawn-claude:latestshows bothlinux/amd64andlinux/arm64).spawn claude local --beta sandboxno longer hangs at the GitHub auth step;docker image inspect ghcr.io/openrouterteam/spawn-claude:latest --format '{{.Architecture}}'reportsarm64.amd64variant of the manifest).🤖 Generated with Claude Code