Skip to content

ci(docker): build multi-arch images (amd64 + arm64)#3392

Merged
la14-1 merged 2 commits intomainfrom
ci-multi-arch-docker-images
May 5, 2026
Merged

ci(docker): build multi-arch images (amd64 + arm64)#3392
la14-1 merged 2 commits intomainfrom
ci-multi-arch-docker-images

Conversation

@AhmedTMM
Copy link
Copy Markdown
Collaborator

@AhmedTMM AhmedTMM commented May 5, 2026

Summary

  • Adds docker/setup-qemu-action + docker/setup-buildx-action to .github/workflows/docker.yml, and sets platforms: linux/amd64,linux/arm64 on the build-push step.
  • Apple Silicon hosts running --beta sandbox will now pull a native arm64 image instead of falling back to Rosetta emulation of amd64.

Why

spawn <agent> local --beta sandbox hangs at the GitHub auth step on M-series Macs. Inside the running container I caught the smoking gun:

root  39  [rosetta] /usr/bin/apt-get apt-get update -qq    # stuck in S state
_apt  43   \_ [rosetta] /usr/lib/apt/methods/http ...
_apt  45   \_ [rosetta] /usr/lib/apt/methods/https ...

github-auth.sh triggers apt-get update to install gh. Under Rosetta x86_64 emulation on arm64, the apt http methods sleep indefinitely.

Side-by-side reproduction (host: arm64, OrbStack):

Image apt-get update + install curl + ca-certs
ubuntu:24.04 linux/arm64 (native) 12s
ubuntu:24.04 linux/amd64 (Rosetta) >5 min, still hung

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 via npm install -g, curl ... | bash, or uname -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

  • Trigger the workflow manually (workflow_dispatch) and verify each spawn-<agent>:latest is published as a multi-arch manifest (docker manifest inspect ghcr.io/openrouterteam/spawn-claude:latest shows both linux/amd64 and linux/arm64).
  • On an Apple Silicon host: spawn claude local --beta sandbox no longer hangs at the GitHub auth step; docker image inspect ghcr.io/openrouterteam/spawn-claude:latest --format '{{.Architecture}}' reports arm64.
  • On an x86_64 host: same flow continues to work (pulls amd64 variant of the manifest).

🤖 Generated with Claude Code

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.
@AhmedTMM AhmedTMM marked this pull request as ready for review May 5, 2026 07:16
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.
Copy link
Copy Markdown
Member

@la14-1 la14-1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a post-build verification step in 7238c26 that greps the pushed manifest for both linux/amd64 and linux/arm64 — catches regressions where setup-qemu/buildx or the platforms flag get dropped. Auto-merging when CI lands.

@la14-1 la14-1 merged commit 3ae6554 into main May 5, 2026
5 checks passed
@la14-1 la14-1 deleted the ci-multi-arch-docker-images branch May 5, 2026 07:27
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.

3 participants