fix(smolmachines): build agent image in launch, not prepare #80

Merged
didericis merged 1 commits from smolmachines-build-in-launch into main 2026-05-27 19:44:54 -04:00
Collaborator

Summary

Starting a smolmachines agent from the dashboard rendered the docker build + smolvm pack create output on top of the curses preflight modal — the build ran before the operator confirmed y/N. Docker's prepare is pure resolution; smolmachines was inconsistent because prepare called _ensure_smolmachine (build → save → crane push → pack create), several seconds of stderr noise before the prompt.

Changes

  • _ensure_smolmachine moves from backend/smolmachines/prepare.py to backend/smolmachines/launch.py. Plus _SMOLMACHINE_CACHE_DIR, _REPO_DIR, and the local-registry / smolvm imports it needs. The function runs immediately before _smolvm.machine_create, so the resulting .smolmachine sidecar path lands as a local in launch, not on the plan.
  • SmolmachinesBottlePlan.agent_from_path: Pathagent_image_ref: str. prepare stashes only the docker tag ($CLAUDE_BOTTLE_IMAGE or claude-bottle:latest); launch resolves it into the artifact at bringup.

This puts smolmachines on the same prepare-vs-launch boundary the docker backend uses. The dashboard's preflight summary draws first, the operator confirms, and then launch runs — whose stderr is routed via _route_op_to_right_pane (in tmux) or via curses.endwin (foreground handoff) so the build output lands cleanly.

Tests

  • tests/unit/test_smolmachines_prepare_image.pytests/unit/test_smolmachines_launch_image.py. Updated to import _ensure_smolmachine from launch rather than prepare.
  • test_smolmachines_provision.py: plan fixture switches agent_from_pathagent_image_ref.

593 unit tests pass.

Stacking

Independent of PR #78 / PR #79 — touches only backend/smolmachines/ and its tests. Can merge in any order.

## Summary Starting a smolmachines agent from the dashboard rendered the `docker build` + `smolvm pack create` output on top of the curses preflight modal — the build ran before the operator confirmed `y/N`. Docker's `prepare` is pure resolution; smolmachines was inconsistent because `prepare` called `_ensure_smolmachine` (build → save → crane push → pack create), several seconds of stderr noise before the prompt. ## Changes - **`_ensure_smolmachine` moves from `backend/smolmachines/prepare.py` to `backend/smolmachines/launch.py`.** Plus `_SMOLMACHINE_CACHE_DIR`, `_REPO_DIR`, and the local-registry / smolvm imports it needs. The function runs immediately before `_smolvm.machine_create`, so the resulting `.smolmachine` sidecar path lands as a local in `launch`, not on the plan. - **`SmolmachinesBottlePlan.agent_from_path: Path` → `agent_image_ref: str`.** `prepare` stashes only the docker tag (`$CLAUDE_BOTTLE_IMAGE` or `claude-bottle:latest`); `launch` resolves it into the artifact at bringup. This puts smolmachines on the same prepare-vs-launch boundary the docker backend uses. The dashboard's preflight summary draws first, the operator confirms, and then `launch` runs — whose stderr is routed via `_route_op_to_right_pane` (in tmux) or via `curses.endwin` (foreground handoff) so the build output lands cleanly. ## Tests - `tests/unit/test_smolmachines_prepare_image.py` → `tests/unit/test_smolmachines_launch_image.py`. Updated to import `_ensure_smolmachine` from `launch` rather than `prepare`. - `test_smolmachines_provision.py`: plan fixture switches `agent_from_path` → `agent_image_ref`. 593 unit tests pass. ## Stacking Independent of PR #78 / PR #79 — touches only `backend/smolmachines/` and its tests. Can merge in any order.
didericis-claude added 1 commit 2026-05-27 19:37:33 -04:00
fix(smolmachines): build agent image in launch, not prepare
test / unit (pull_request) Successful in 27s
test / integration (pull_request) Successful in 39s
7afedaabf3
When starting a smolmachines agent from the dashboard the
docker-build output rendered on top of the curses preflight
modal — the build was kicked off before the operator had
confirmed launch. The docker backend's `prepare` is pure
resolution (no docker calls); smolmachines was inconsistent
because `prepare` called `_ensure_smolmachine` which ran
`docker build` → `docker save` → `crane push` → `smolvm pack
create`, several seconds of stderr noise rendered before the
y/N prompt.

Move the pipeline:

- `_ensure_smolmachine` (+ `_SMOLMACHINE_CACHE_DIR` + `_REPO_DIR`
  + the local-registry / smolvm imports) moves from
  `backend/smolmachines/prepare.py` to
  `backend/smolmachines/launch.py`. Called right before
  `_smolvm.machine_create` so the resulting `.smolmachine`
  sidecar path lands as a local in `launch`, not on the plan.

- `SmolmachinesBottlePlan.agent_from_path: Path` becomes
  `agent_image_ref: str`. `prepare` stashes only the docker tag
  (`$CLAUDE_BOTTLE_IMAGE` || `claude-bottle:latest`); `launch`
  resolves it into the artifact at bringup.

This puts smolmachines on the same prepare-vs-launch boundary
the docker backend uses: the preflight summary in the dashboard
prints, the operator confirms, then `launch` runs — and its
stderr is routed via `_route_op_to_right_pane` (in tmux) or via
`curses.endwin` (foreground handoff) so the build output lands
cleanly.

Tests:
- `tests/unit/test_smolmachines_prepare_image.py` →
  `tests/unit/test_smolmachines_launch_image.py`, updated to
  import `_ensure_smolmachine` from `launch` rather than
  `prepare`.
- `test_smolmachines_provision.py`: plan fixture switches
  `agent_from_path` → `agent_image_ref`.

593 unit tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
didericis approved these changes 2026-05-27 19:44:45 -04:00
didericis merged commit 5e0130b56f into main 2026-05-27 19:44:54 -04:00
didericis deleted branch smolmachines-build-in-launch 2026-05-27 19:44:54 -04:00
Sign in to join this conversation.