Skip to content

feat(bundle): a registry image with its build context beside it, and bundle init --image-ref - #405

Merged
earakely-scale merged 3 commits into
mainfrom
feat/bundle-image-refs
Oct 30, 2026
Merged

earakely-scale merged 3 commits into
mainfrom
feat/bundle-image-refs

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

What

A bundle can name an image in a registry and keep its build context beside it:

image = { ref = "<registry>/<repo>:<tag>@sha256:<digest>", dockerfile = "Dockerfile" }

An image folder can also hold a Dockerfile beside the ref in its artifact.toml, which it used to refuse. A run pulls the image by its digest and never builds it. The context is there to read or rebuild, and a deploy builds from it only when it can't pull the image, as it already does for a published agent image.

agent-env bundle init can write images this way. --image-ref ID=REF (or image_refs= on import_task and import_eval) writes the stored image ID as the registry image REF, with the part of its stored context its Dockerfile reads beside it.

  • Tags: REF may name a tag alone; the import pins it to the digest its registry serves now, once per image, so nobody has to look a digest up. A ref giving a digest is written as given, without asking the registry.
  • Version pinning: it skips pinning the Dockerfile to the stored image's versions, since the run pulls the image, so the import never reads the stored tarball.
  • No context: an image with no context, or one whose context can't be written, is written as the ref alone.
  • Refusals: a ref that doesn't name its registry, gives a digest that isn't whole, names a tag its registry can't pin, or names an image the import writes none of, fails the import.

The point is delivering a bundle the way Harbor is delivered: the export pushes each image to a private registry the recipient is granted, and the bundle names it by digest.

How

  • Writing: put_ref with a context but no digest now pins through the registry, then records the name and the digest apart, the shape a published image has. Existing callers all pass a digest, so they're unchanged.
  • Ledger: it covers the context's files, so editing the context rewrites the image. Rewriting keeps the earlier pin while the ref is the same.
  • Reporting: the import lists such an image as "pulled as REF, its build context beside it". Its README says pulled images are pulled by digest, and names their registries among what a machine needs. The machine-needs bullets now sit inside that list instead of after the images paragraph.

Testing

  • Unit tests cover resolve, the write, the ledger and pin reuse, the dry-run line, the import (with its refusals and the CLI), and an import followed by a run writing the image at the given digest without building it.
  • End to end on local Docker 29, with the echo-mcp example and a local registry:2 standing in for the delivery registry:
    1. Ran it into the store and pushed its image.
    2. Ran bundle init --image-ref.
    3. Deleted the image from Docker.
    4. agent-env run from an empty state root pulled the image by its digest, built nothing, and the verifier passed.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no new blocking issue was found.

Summary

Adds registry-backed bundle images with optional build contexts and bundle init --image-ref.

  • Bundles can keep a Dockerfile context beside a registry image.
  • Bundle imports can use digest-pinned registry refs for stored images.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["bundle init --image-ref ID=REF"] --> B{"REF includes a digest?"}
  B -->|Yes| C["Check digest format"]
  B -->|No| D["Resolve tag through registry"]
  C --> E["Keep one pinned reference per image ID"]
  D --> E
  E --> F{"Context can be written?"}
  F -->|Yes| G["Write reference and pruned context"]
  F -->|No| H["Write reference alone"]
Loading

Reviews (3) · Last reviewed commit: "feat(bundle): bundle init --image-ref pi..." · Reviewed by Greptile

…bundle init --image-ref

An image key can be `{ ref = "<registry>/<repo>:<tag>@sha256:…", dockerfile = "Dockerfile" }`,
and an image folder can hold a Dockerfile beside its ref. A run pulls the image by its digest and
never builds it; the context is kept for reading or rebuilding, which a deploy does only when it
can't pull. put_ref given a context and no digest pins through the registry and records name and
digest apart, as a published image does; the ledger covers the context's files.

`agent-env bundle init --image-ref ID=REF` (image_refs= on import_task / import_eval) writes the
stored image ID as that digest-pinned registry image with its pruned context beside it, skipping
version pinning, and refuses a ref that isn't pinned or names no image the import writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/agent_env/bundle/_images.py Resolved
Comment thread src/agent_env/bundle/importer.py Resolved
Comment thread src/agent_env/bundle/importer.py Resolved
Comment thread src/agent_env/bundle/_import_report.py Resolved
earakely-scale and others added 2 commits October 29, 2026 22:08
…efuse what can't be written

- A Dockerfile an image given a ref shares with another image is no longer pinned to the other
  image's versions, since a deploy that can't pull the ref'd image rebuilds it from that file.
- A context in a store this config can't read no longer aborts the import: its download says why,
  and an image given a ref is written as the ref alone.
- A given ref must pin a whole sha256 digest (64 hex digits).
- The README gives the build paragraph only when an image was written from its context, and the
  pulled one whenever an image is pulled, ref-only ones included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A ref given for an image may now name a tag alone: the import pins it to the digest its registry
serves now, with the configured image store's credentials, once per image, and writes that. A ref
giving a digest is written as given without asking the registry; one whose digest isn't whole, or
a tag its registry can't pin, still fails the import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit 812e5a1 into main Oct 30, 2026
26 checks passed
@earakely-scale
earakely-scale deleted the feat/bundle-image-refs branch October 30, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant