Repository navigation
Publish CI's Linux opam root for coding agents - #13127
Conversation
extra/agent-setup.sh sets up OCaml 5.3.0 and the compiler's opam dependencies in /opt/opam and builds haxe. It downloads a prebuilt opam root from the agent-ocaml-deps release when one matches haxe.opam and the OS, and builds from source otherwise. The new Agent OCaml deps workflow publishes those prebuilt roots for x86_64 and arm64. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
|
I have a question about how all this interacts with our CI because it's not clear to me what's being built how often: am I understanding correctly that when we push development, this checks if our OCaml dependencies changed and in that case rebuilds a tarball? And otherwise it just downloads the one that was previously built? If that's the case, shouldn't there be an interaction with our ubuntu CI runners? They also need an OCaml environment in order to build haxe, so I'd like to make sure that we're not building and caching things in different places at the same time. |
|
Almost. Here's exactly what happens:
So you're right that it duplicates CI. Right now there are three independent opam builds:
There's one catch in merging them. A. Make
B. Keep the build separate and only share the logic.
I'd go with A. It does touch Generated by Claude Code |
|
I think that makes sense to me, please go ahead and implement it like that so we can review it! |
linux-build now gets its OCaml toolchain through extra/agent-setup.sh instead of an actions/cache of ~/.opam. It downloads the prebuilt opam root from the opam-root release when one matches, and otherwise builds it; on pushes to development, the new publish-opam-root job uploads what was built. Agents and the Copilot setup download the same archive, so the separate agent-ocaml-deps workflow is gone. The archive is built on Ubuntu 22.04 (linux-build's runner) and keyed on the OCaml version, that OS, the architecture, haxe.opam and a manual revision. The script checks that a downloaded root actually works and falls back to building from source if it doesn't. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
|
Done in ba1ee89. I've updated the description to match. In short:
The Two trade-offs worth looking at:
Generated by Claude Code |
conf-neko needs the neko binary when the opam root is built from source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
This should be a rare occurrence so I think it's fine.
I have no intuition for how much 260 MB is compared to what it's already doing. Any ideas? And would there be a straightforward way to avoid this? |
The deploy job downloaded every artifact of the run, which on runs that rebuild the opam root includes two ~260 MB archives it doesn't use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
|
Sizes: Avoiding it: Status: the arm64 Generated by Claude Code |
|
This seems really overly complicated, why can't the agent setup just reuse the existing linux cache? |
|
@tobil4sk Fair question. The short answer is that the
So to share CI's build with them, it has to be published somewhere downloadable without a token. Workflow artifacts need an authenticated API call to download; release assets don't. Hence the release. Two more reasons it can't just be the existing cache, even if it were downloadable:
Once something is published anyway, having If that still seems like too much for what it buys, there are simpler options:
Happy to go either way. Simn, your call too since you asked for the current shape. Generated by Claude Code |
Why thank you that I get a say in this! x) Conceptually, I don't find this very complicated: one thing builds the cache and then several other things use it. Whether or not it's the absolute simplest way to go about it is something I can't answer, but I actually find downloading and extracting a tarball much more palpable than whatever is going on in GitHub actions. I was fine with the tighter coupling during the Copilot days, but IMO it's good to not rely so much on a single infrastructure in the first place. |
|
The agent setup problem seems like a separate issue from haxe ci, and I would prefer to avoid replacing a simple 3 line step in The I think using a platform like docker would be more appropriate for cloning dev environments (maybe there is some more trendy agent-oriented platform these days). |
|
I don't really care how we solve this, so if there's a convenient Docker solution that would be fine by me. My main concern (other than spending all my Claude tokens on OCaml setup...) is to not duplicate work, so this seemed like the most natural approach. |
|
@tobil4sk Both objections are fair: On Docker: it would be the natural fit if the agent platforms let us pick the image. As far as I can tell from the documentation available to me, Claude Code's cloud environments don't offer a custom base image; you get their standard image plus a setup script. Copilot's setup is a GitHub Actions job on a stock runner. So in both cases the image would have to be pulled and unpacked in the setup step. To get OCaml out of it we'd still be extracting files from an archive, just with a registry, a Dockerfile and image tooling added on top. A middle ground that keeps CI the way it was and still avoids a second build:
So CI's build setup stays in Generated by Claude Code |
The middle ground sounds good, it also allows changing the agent parts freely (like the extra/agent-setup.sh) without affecting linux-build. |
|
That works for me too, let's do it! |
Following the review: linux-build goes back to its actions/cache and the inline opam init/install steps, with the opam root moved to /opt/opam so that it can be reused elsewhere. On pushes to development it packages the root when no archive for the current key is published yet, and publish-opam-root uploads it and deletes the archive it replaces. extra/agent-setup.sh is now only used by agents and the Copilot setup. It no longer assumes a switch name, so it works with the root CI builds with opam init -c, and it never deletes an existing opam root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
|
Could you clarify what the "on a cache miss" part in your design was about and how it relates to the new |
|
Switched to the middle ground in 8b633f0 and updated the description:
Tested locally:
This push's CI run is the first one using the cache at Generated by Claude Code |
|
Good catch, the implementation differs from what I wrote there. In the proposal, "cache miss" meant: only package when Cache hit, but nothing published (a cache-miss condition would never publish):
Cache miss, but already published (a cache-miss condition would re-upload 260 MB for nothing):
So the step asks the release directly: one HTTP HEAD request on each Generated by Claude Code |
As suggested in review: linux-build no longer calls extra/agent-setup.sh. On development pushes it uploads the opam root as opam-root-<arch>, and publish-opam-root names it with the script, skips it if that asset is already published, and otherwise uploads it and deletes older ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq
|
Checked this after the merge in a fresh cloud agent container (Ubuntu 24.04, x86_64), at dcaad27: the prebuilt opam root works, and no OCaml build is needed. I moved the existing
The container's own environment setup had already set itself up from the same archive before this check: Generated by Claude Code |
Coding agents usually start in a fresh Ubuntu container with no OCaml. Ubuntu only ships OCaml 4.14, so every session has to build OCaml 5.3.0 and all opam dependencies from source, and agents often lose more time getting
opam init, the switch andPATHright. CI'slinux-buildalready builds exactly this opam root, but itsactions/cacheis only reachable from inside GitHub Actions.This PR has CI publish the opam root that
linux-buildbuilds, and gives agents a script that downloads it.What's in it
main.ymllinux-buildkeeps itsactions/cacheand inlineopam init/opam installsteps. The opam root moves from~/.opamto/opt/opam, because opam roots aren't relocatable and agents need a fixed path.development,linux-buildtars the root and uploads it as an artifact namedopam-root-<arch>(kept for one day).publish-opam-rootjob asksextra/agent-setup.shfor the asset name. If that asset isn't on the rollingopam-rootprerelease yet, the job uploads it (about 260 MB with zstd) and deletes the one it replaces, so the release holds one archive per architecture.deployonly downloads the*Binariesartifacts, so it doesn't pull the archives.extra/agent-setup.sh(agents and Copilot only; CI doesn't run it)--no-apt)./opt/opamand checks that it works. If there's none or it doesn't work, it builds from source with the same steps aslinux-build.~/.bashrcand~/.profile(skip with--no-profile).make haxe(skip with--no-build).haxe.opamand aREVISIONnumber. BumpREVISIONto publish a fresh archive, e.g. to pick up newer dependency versions.copilot-setup-steps.yml: uses the script instead of its own opam cache, and sets up Neko before the OCaml dependencies (conf-nekoneeds it).AGENTS.md: tells agents to run the script instead of setting up OCaml by hand.The archive is built on 22.04 and used on 24.04 by agents and Copilot. That should work since glibc is backwards compatible, and the script falls back to a from-source build if the unpacked toolchain doesn't run.
Measured
make haxe(4-core Ubuntu 24.04 container)make haxe(same container)The archive path and the fallback were tested locally with a local archive, and the publish logic with a stub
gh. The real publish and download can only be tested after the first push todevelopment.After merging, the Claude Code cloud environment's setup script can be
cd haxe && bash extra/agent-setup.sh.🤖 Generated with Claude Code
https://claude.ai/code/session_01Va4FXDYunkfcakJ5BFq4hq