Commit Graph

1 Commits

Author SHA1 Message Date
didericis-claude 1fa17d1822 feat(smolmachines): build agent image from repo Dockerfile (PRD 0023 chunk 4c)
test / unit (pull_request) Successful in 21s
test / unit (push) Successful in 21s
test / integration (push) Successful in 42s
test / integration (pull_request) Successful in 41s
Replaces the alpine:latest placeholder with a real claude-bottle
agent image, converted into a .smolmachine artifact via an
ephemeral local OCI registry.

Why the registry hop: smolvm pack create only accepts OCI registry
refs. Empirically it rejects docker-daemon://, oci-layout://,
docker-archive: tarballs, and every other transport tested — the
crane backend treats anything with a scheme prefix as a registry
hostname. To convert a locally-built docker image into a
.smolmachine we have to push it somewhere smolvm can pull from.
Smallest path: bring up registry:2.8.3 bound to 127.0.0.1:<random>,
docker tag + docker push into it, smolvm pack create --image
localhost:<port>/claude-bottle:<id>, tear down the registry.

The .smolmachine is cached under
~/.cache/claude-bottle/smolmachines/ keyed by the docker image ID
(first 16 hex chars of the sha256), so a Dockerfile change picks
up a new image ID and invalidates the cache. Unchanged rebuilds
skip the whole build → registry → pack pipeline.

This puts `docker build` in smolmachines prepare (the docker
backend defers it to launch). Necessary because pack_create needs
the image ID to derive the cache key, and prepare is the only
hook ahead of launch that runs once per slug.

Adds:
- claude_bottle/backend/docker/util.py: image_id / tag / push
  helpers (thin docker CLI wrappers).
- claude_bottle/backend/smolmachines/local_registry.py:
  ephemeral_registry() context manager; pins registry:2.8.3 by
  digest, binds 127.0.0.1::5000 (loopback-only), force-removes on
  exit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 13:51:02 -04:00