ci: multi-arch (linux/arm64) support for the Docker image - #36
Merged
Conversation
Native GitHub-hosted arm64 runner (ubuntu-24.04-arm, GA and free for public repos), not QEMU — no emulation anywhere in this pipeline. Both legs run the same 4 existing smoke tests unmodified. Renames the job's check name (now suffixed with the platform on both legs, including amd64) — required_status_checks needs a matching update after merge, same as docker-build/mcpb-build's own precedent. See docs/distribution/docker-arm64 spec. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Splits the single linux/amd64 build+push into 3 jobs: - docker-publish (matrixed linux/amd64 + linux/arm64, native runners — ubuntu-24.04-arm for arm64, no QEMU) builds and pushes each platform by digest only, no final tag yet. - docker-publish-merge combines both digests into one multi-arch manifest via `docker buildx imagetools create`, applying the real X.Y.Z + latest tags. Verifies the published manifest lists both platforms before finishing. Digests cross the job boundary via upload/download-artifact — matrix-job outputs don't reliably aggregate into a downstream job's needs.*.outputs, this is docker/build-push-action's own documented pattern for this case. End users see no change: `docker pull ghcr.io/helgdemidov/refigure:latest` on Apple Silicon now resolves the arm64 layer automatically (one OCI image index under the existing tags). The actual GHCR push path (imagetools create/inspect) can only be fully verified live on the next real tagged release — same constraint the original docker-publish job had. See docs/distribution/docker-arm64 spec. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Both the Features bullet and the Docker accordion body now note the linux/amd64 + linux/arm64 multi-arch manifest — docker pull resolves the right layer automatically, including on Apple Silicon, no new commands for users. See docs/distribution/docker-arm64 spec. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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 & why
The Docker image (
ghcr.io/helgdemidov/refigure) waslinux/amd64-only,an explicit non-goal in the original Docker distribution spec. Reversed
based on live-verified evidence, not assumption:
document-interchange format; Apple's iWork has asymmetric compatibility
with Office (Office can't open
.pages/.numbersat all), so Mac userssharing externally are forced through
.docx/.xlsxregardless. macOSenterprise share is growing, and Microsoft brought native Office to
macOS for enterprise in Jan 2025. PyPI/uvx/MCP-server already work
natively on Apple Silicon (arm64 Python wheels) — Docker was the one
format left depending on QEMU emulation for Apple Silicon.
(
docling-serve,unstructured) already publish official multi-archimages including arm64; 3 of 5 publish no official image at all.
docker buildx build --platform linux/arm64of the actual (unmodified)Dockerfilesucceeded withzero dependencies falling back to a source build — every dependency
(
lxml,pypdfium2,pydantic-core,jiter,cryptography,pillow,cffi,rpds-py) resolved a realaarch64wheel. Theresulting image was smoke-tested under
--platform linux/arm64:refigure --help,refigure-mcp --help,soffice --versionallpassed. GitHub-hosted
ubuntu-24.04-armrunners are GA and free forpublic repos — CI builds arm64 natively, no QEMU anywhere in the
pipeline.
Full spec (local-only,
docs/is gitignored):docs/distribution/docker-arm64/docker-arm64-2026-08-22.md.Changes
ci.yml:docker-buildmatrixed acrosslinux/amd64(ubuntu-latest)linux/arm64(ubuntu-24.04-arm) — same 4 existing smoke tests onboth legs, unmodified logic. Note: this renames the job's check
name on both legs (now platform-suffixed) —
required_status_checksneeds a matching update after merge (replace the old name, add the new
arm64 leg), same precedent as the original
docker-build/mcpb-buildadditions.
publish.yml:docker-publishsplit into a matrixed digest-push job(per platform, native runners) + a new
docker-publish-mergejob thatcombines both digests into one multi-arch manifest via
docker buildx imagetools create, under the existingX.Y.Z/latesttags. Verifiesthe published manifest lists both platforms before finishing. The
actual GHCR push path can only be fully verified live on the next real
tagged release (same constraint the original job had).
README.md: Docker feature bullet + accordion body now mention themulti-arch manifest. No new commands for end users —
docker pullresolves the right layer automatically, including on Apple Silicon.
Test plan
ruff check ./ruff format --check ./mypy refigure— cleanpytest --cov— 684 passed, 4 skipped, 99% coverage.github/workflows/{ci,publish}.yml— YAML-validated, jobdependency graph checked (
publish → docker-publish → docker-publish-merge)docker buildx build --platform linux/arm64of theunmodified
Dockerfile— success, zero source-build fallbacksrefigure --help,refigure-mcp --help,soffice --version) — all passed(
docker buildx imagetools create/inspect) — only possible onthe next real tagged release, not before
After merge
required_status_checksneeds updating (remove the old singledocker-buildcheck name, add both platform-suffixed names) — sameprocess as prior distribution-format PRs, done post-merge once the new
check names exist on
main.🤖 Generated with Claude Code