feat(smolmachines): smolvm subprocess wrapper (PRD 0023 chunk 2b) #65
Reference in New Issue
Block a user
Delete Branch "prd-0023-chunk-2b-smolvm-wrapper"
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?
Summary
Chunk 2b: one thin Python function per smolvm CLI subcommand the launch flow needs. Mocked unit tests cover argv construction; a small integration smoke probes the real binary so we catch CLI drift across smolvm releases.
API
The wrapper hides the CLI's inconsistent name-flag style behind a uniform
name=kwarg (positionalNAMEoncreate/delete,--name NAMEonstart/stop/exec/status).Two return shapes
machine_execreturnsSmolvmRunResult(returncode, stdout, stderr)— callers (most importantlyBottle.exec) need to see the in-VM command's exit status, not just whether smolvm itself ran.SmolvmErroron non-zero. Failing to start a VM is fatal to the launch flow, not something callers branch on.Tests
tests/unit/test_smolmachines_smolvm.py) mockingsubprocess.run: argv shape per subcommand (with the positional-vs-flag inconsistency locked down),SmolvmErrorraising,SmolvmRunResultpassthrough on exec, empty-pathcpno-op.tests/integration/test_smolmachines_smolvm_smoke.py) against the real smolvm binary (gated on Darwin + smolvm on PATH + notGITEA_ACTIONS):smolvm --helpresponds,machine ls --jsonparses as a list (the contract chunk 4'slist_activewill consume).531 unit tests passing. Real-smolvm smoke green locally.
Chunk 2 remaining
sidecar_bundle.py— per-bottle docker bridge create + bundle container with pinned IP.launch.pyend-to-end (bundle + VM bringup +Bottle.execviamachine_exec) + integration smoke + the localhost-reach + egress-port-bypass probes.claude_bottle/backend/smolmachines/smolvm.py — one thin Python function per smolvm CLI subcommand the launch flow needs: - pack_create(image, output) → smolvm pack create - machine_create(name, from_path, smolfile) → smolvm machine create - machine_start(name) → smolvm machine start - machine_stop(name) → smolvm machine stop - machine_delete(name) → smolvm machine delete -f - machine_exec(name, argv, env, workdir, timeout) → smolvm machine exec - machine_cp(src, dst) → smolvm machine cp - is_available() → shutil.which check The wrapper hides the CLI's inconsistent name-flag style (positional NAME on create/delete, --name on start/stop/exec/ status) behind a uniform `name=` kwarg. Two return shapes: - SmolvmRunResult (returncode + stdout + stderr) from machine_exec, because callers care about the in-VM command's exit code. - Raises SmolvmError on non-zero for all other commands; failure to create/start/stop a VM is fatal to the launch flow, not branched on. Tests: - 15 unit cases mocking subprocess.run, covering argv shape per subcommand (the --name vs positional inconsistency locked down), SmolvmError on non-zero for non-exec paths, SmolvmRunResult passthrough on exec, empty-path cp no-op. - 2 integration cases against the real smolvm binary (gated on Darwin + smolvm on PATH + not GITEA_ACTIONS): smolvm --help responds, machine ls --json parses as a list (the contract chunk 4's list_active will consume). 531 unit tests passing. Real-smolvm smoke green locally. Bundle bringup + launch wiring + the localhost-reach / egress-port-bypass probes land in chunks 2c + 2d. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>