Repository navigation
feat(bundle): write a built image as its build context when its deploys build it in their VMs - #136
Conversation
…ys build it in their VMs Preflight now decides how each image the bundle builds is written. When every deploy runs it on the local provider it is built on this machine, as before. When every deploy runs it on providers whose VMs build it, it is written with put_context and no local docker. A run deploying it both ways, or on a provider that runs an image by name, is refused. The ledger hashes the form and platform only for a build context, so existing rows stay reused, and the dry run lists each built image's form. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| by_name = ([link for link in _links(provider) if isinstance(link, ModalSandboxProvider)] if GATEWAY in kinds | ||
| else _links(provider)) | ||
| self._by_name(where, by_name, images) | ||
| self._use(where, _links(provider), by_name, images) |
There was a problem hiding this comment.
Plugin environment skips image choice
If a plugin environment provider deploys a bundle-built image on a remote VM, _env returns before this new _use call. Preflight never selects the build-context form, so materialization builds the image locally and the remote VM cannot build it from the bundle's context. Include these deploys in the form decision or refuse them before writing.
Knowledge Base Used: Bundle authoring, installation, and execution
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/bundle/preflight.py
Line: 200
Comment:
**Plugin environment skips image choice**
If a plugin environment provider deploys a bundle-built image on a remote VM, `_env` returns before this new `_use` call. Preflight never selects the build-context form, so materialization builds the image locally and the remote VM cannot build it from the bundle's context. Include these deploys in the form decision or refuse them before writing.
**Knowledge Base Used:** [Bundle authoring, installation, and execution](https://app.greptile.com/scale-ai/-/custom-context/knowledge-base/scaleapi/agentenv-framework/-/docs/bundle-authoring-and-execution.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
This is unchanged here: a deploy_env on a plugin's env provider returned before the image checks before this PR too, so its images were never checked by preflight, which can't tell how a plugin's provider runs them. Such a deploy is left to deploy_env's own preflight, as before, and the image is written as it was before this PR (built on this machine).
There was a problem hiding this comment.
That’s a valid distinction. Plugin environment providers are intentionally left to deploy_env’s own preflight because this bundle preflight cannot know their deployment semantics; the early return preserves the existing behavior, including locally materializing their images. Since this PR does not change that contract, Issue 2 is not a regression and does not need a fix. I’m withdrawing that finding.
…to build it in Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@greptileai review |
Until now, a bundle always built its images on this machine. Preflight refused them on any remote provider, so a bundle with its own agents or servers could run only with
--sandbox local.This PR has the bundle write each image in the form its deploys can run:
put_context, so the image is only its build context. Each VM builds it (feat(images): build context-only images in VM sandboxes #133), and no local docker is needed.modal_vm,local;The decision belongs to preflight, which already resolves each deploy's provider.
preflight_runreturns the ids of the images it writes as build contexts, andmaterialize(..., contexts=)writes those withput_context.Ledger: a build context's digest also covers its form and its platform (
linux/amd64). Both are added only for a build context, so an image built on this machine hashes exactly as before. Every existing ledger row stays reusable, and the golden digests don't change. Switching an image's form rewrites it and its agent or env, and says why: "now written as a build context, which its VMs build, not an image built on this machine".Dry run: a new "Images:" section lists each built image and its form.
Tests
source_digestmatches the folder;@localcontext, which no store can sign, pushed over exec and then built.Live, beta_scale,
@localids onlyCOPY .with.dockerignoreand a link, a Dockerfile in a subfolder, multi-stage) plus an MCP server through the gateway, run with--sandbox beta_scale.--sandbox localwould rewrite each image with the form-switch reason.--sandbox modalandbeta_scale,modalare refused at every deploy before anything is written.Known limits
modalis refused for these images. The next change makes Modal build them.🤖 Generated with Claude Code

Confidence Score: 5/5
The PR appears safe to merge; the earlier provider concern is addressed and no new issue was established.Fix with agent prompt
Summary
Bundles can now write built images as contexts for VM providers to build, while local deployments keep using local image builds. Preflight selects the form from each image’s deployments, and dry runs show the planned form.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR P[Preflight checks deploys] --> L[Local only] P --> V[VM providers only] P --> R[Mixed or unsupported] L --> B[Build with local Docker] V --> C[Write build context] R --> X[Refuse before writing] B --> D[Ledger records image] C --> DReviews (3) · Last reviewed commit: "fix(bundle): refuse a build context on a..." · Reviewed by Greptile