mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[PR #347] [MERGED] feat(image): build and publish reusable images with the CLI #367
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#367
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/kvcache-ai/AgentENV/pull/347
Author: @Primary33
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/16/2026
Merged by: @yingdi-shan
Base:
main← Head:feat/local-image-builds📝 Commits (1)
2c295ebfeat: build and publish reusable images with the CLI📊 Changes
28 files changed (+2169 additions, -206 deletions)
View changed files
📝
crates/aenv/src/client/templates.rs(+10 -0)📝
crates/aenv/src/commands/build.rs(+116 -32)📝
crates/aenv/src/commands/pull.rs(+1 -0)📝
crates/aenv/src/main.rs(+1 -1)📝
docs/src/concepts/sandboxes/starting.md(+56 -1)📝
scripts/buildkit/test.py(+33 -0)📝
src/api/generated/src/models.rs(+37 -1)📝
src/api/impls/image_build.rs(+223 -85)📝
src/api/impls/image_build/cleanup.rs(+9 -3)➕
src/api/impls/image_build/record.rs(+206 -0)📝
src/api/impls/image_build/tests.rs(+388 -5)📝
src/api/impls/image_build/worker.rs(+5 -5)📝
src/api/impls/template.rs(+84 -12)📝
src/api/openapi.yml(+21 -4)📝
src/api/proxy.rs(+3 -2)📝
src/bin/server.rs(+2 -2)📝
src/digest.rs(+10 -0)📝
src/image/buildkit.rs(+1 -6)📝
src/image/cache/graph.rs(+69 -37)📝
src/image/cache/service.rs(+78 -2)...and 8 more files
📄 Description
What
Build and publish reusable OverlayBD images through the shared repository with
aenv build --image --name NAME[:TAG] [--tag TAG]... CONTEXT, and reference them asaenv/name:tagor by digest.Image builds reuse the template build API instead of adding build endpoints:
POST /v3/templateswith"imageOnly": truecreates the build, and the existing builder, status, logs, and delete endpoints drive it. Image tags belong to their image name, like E2B template tags, and a build points its tags at the image it publishes.Why
Users need a complete image-building flow whose results survive local cache eviction and resolve on another repository-backed node. A digest alone forces every consumer to copy a new reference after each rebuild, so tags give a published image a mutable name while running workloads keep the immutable digest (review feedback in #378).
Reusing the template build protocol keeps one builder lifecycle, one gateway routing model, and one status/logs surface for both kinds of build.
Related issue
Design proposal: #378.
Builds on #386 (merged), which moved the layer reference types and the volume backing config out of
snapshot. The tag management API (#387) builds on this change.Image-build foundation for the four-part replacement of #325. Independent of Compose runtime (#349); the image catalog (#359) and Compose builds (#348) build on this change and will be rebased onto it.
Scope and non-goals
Standalone image CLI, imageOnly builds on the template build API, image publication and resolution, cache ownership, build-time tags, and
aenv/name:tagresolution. Assigning, listing, and deleting tags after a build is #387; listing image names and inspecting or deleting images by digest is #359. Protected tags and reclamation of unreferenced layers are out of scope.Design and behavior changes
Builds:
POST /v3/templateswithimageOnly: truerequiresname(nameorname:tag);tagsadds more tags, and no tag meanslatest.cpuCount/memoryMBare rejected. The response carriesnamesandtags.images/builds/{buildID}.json, not a template record, so template listings and aliases are unaffected andGET /templates/{id}returns 404 for it. Status moves waiting → building → ready/error through the same compare-and-swap pattern as template records, which also excludes a start on another node.PUT /templates/{id}/builds/{id}/builderstarts the worker and rejectsstartCmd/readyCmdfor imageOnly builds. The BuildKit tunnel,DELETE …/builder,…/status, and…/logswork unchanged; a ready status reportsimageDigest. BuildKit builds for the worker's own platform, which is the server's, as for template builds.DELETE /templates/{id}removes an imageOnly build's record and logs and keeps the published image and its tags.Images:
aenv build --imagecontains onlysha256:<64 hex digits>, the digest of the canonical OverlayBD description; diagnostics, including the assigned tags, go to stderr.images/descriptions/{digest}.jsonare committed beforeready; local paths are materialized during resolution. Only commit-store-owned files are tracked as local hard commits.aenv/name[:tag]is accepted wherever asha256:reference is. The resolver reads the tag and continues with its digest, so node caches, sandboxes, and snapshots record only the digest and a moved tag never changes an existing workload.Tags:
--name NAME:TAGand every--tag TAGat its image, so a tag always points to an image built under its name.images/tags/{name}/{tag}.jsonas{imageDigest, createdAtUnixMs}; #387 reads and manages the same documents.Layering and repository:
Repositoryor backend methods are added. With the moves in #386,ImageResolver::publish_imagetakes the layer-storing step as a closure (the API passessnapshot::store::store_volume_layers), soimagedoes not depend onsnapshotandmodule_cyclesstays acyclic. The server passes the repository when it builds the resolver (ImageResolver::with_repository).DocumentKey::Imageholds a digest that onlyDocumentKey::imagecan construct, so an image key cannot escape the repository. Image documents share theimages/root, and no collection prefix contains another.Gateway: no changes. imageOnly builds use the template build routes.
Compatibility and operations
imageOnlyonTemplateBuildRequestV3,imageDigestonTemplateBuildInfo). Short references starting withaenv/now name image tags instead of resolving through the search registries; fully qualified references such asdocker.io/aenv/...are unchanged. A baresha256:image now means a published image description.images/descriptions/,images/builds/, andimages/tags/{name}/.Validation
Rebased onto
b086553(main with #386). The checks below ran on2238155, whose tree is identical to2c295eb; the ones marked "via #387" ran on #387 at06ec1d5, which contains this change. Run on a Linux test host as a non-root user with isolatedAENV_TEST_STATE_DIRandAENV_TEST_DEPS_PATH:make fmtmake clippymake test-unitmake -C services test(required whenservices/changes)maketargetCommands and results:
Skipped checks and reasons: no
services/changes. The integration test config sets[pool.block] enabled = true, because with a config file the ublk daemon reads pool settings only from that file and a partial file disables the pool; this is already the case on main. The cross-node check ran as two isolated servers on one host, and no arm64 host was available. Benchmarks: not applicable.Risks and reviewer notes
Review the imageOnly branches of the template build endpoints (
src/api/impls/template.rsBuildRecord,src/api/impls/image_build.rs,src/api/impls/image_build/record.rs), publication and resolution (src/image/resolver.rs,src/image/mod.rs,src/image/catalog.rs), and cache ownership (src/image/cache/).Tag writes are last-writer-wins, and a tag is resolved to a digest once per launch. Deleting an imageOnly build checks for an active build only on the node that serves the request, like template deletion. Failed publication may leave immutable layers for reuse.
Changes since the last review:
--opt platform=linux/amd64.finish_image_buildchange (the failure-path wait and the log flush order).images/tags/andimages/builds/, and descriptions toimages/descriptions/, so every image document shares one root.Debugstays becausedyn Repositoryis notDebug);allocate_image_buildusesbuild_recordandBuildRecord; removed the CLI'sparse_image_tag;ImageTagis{name, tag}; image code shares onenow_unix_ms.volume/catalog.rsandsnapshot/catalog.rs.Checklist
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.