Skip to content

Building VM

The computer an agent works on is a Linux VM run by virtx. Ailoy depends on virtx, and your code uses it directly:

  • Python: the virtx package (import virtx), which pip install ailoy-py installs too
  • Node.js: @brekkylab/virtx (npm install @brekkylab/virtx beside @brekkylab/ailoy)
  • Rust: the virtx crate (ailoy::console::ConsoleClient is the same type as virtx::console::ConsoleClient)

A ConsoleClient built with virtx is handed to an AgentBuilder as is, and the agent shares its session. The session stays the console’s:

  • Closing the agent leaves the console open; closing the console ends the session for the agent too, whose next command then fails.
  • Your own calls on the console and the agent’s take turns, one call at a time.

Two clients do the work:

  • ImageClient builds the VM’s disk image from a Recipe and manages the built images.
  • ConsoleClient boots a VM from an image and runs commands in it. This is what the agent gets.

A Recipe is a base image plus steps, much like a Dockerfile. ImageClient builds it and stores it under a name, so a console can boot from it later without building it again.

import asyncio
from virtx import ImageClient, ImageSource, Recipe, ensure_virtx
async def main() -> None:
# Fetches virtx's server into its cache the first time; a no-op after.
await ensure_virtx()
async with await ImageClient.try_new() as images:
recipe = Recipe("python:3.12-slim-trixie").step("pip install matplotlib")
built = await images.build(recipe, "plot:latest")
print(built.reference, built.digest)
for image in await images.list():
print(image.digest, image.refs)
# Remove it by its reference (or ImageSource.digest(...) for its digest).
await images.remove(ImageSource.reference("plot:latest"))
asyncio.run(main())

You don’t have to build ahead of time: passing a Recipe straight to a console builds it on first use.

ConsoleClient.builder() sets up the VM: the image to boot, host directories to mount, network access, CPUs, memory and GPU. build() boots it, and exec runs a command in it.

import asyncio
from virtx import ConsoleClient, ImageSource
async def main() -> None:
console = await (
ConsoleClient.builder()
.image(ImageSource.reference("plot:latest"))
.mount("./artifacts", "/artifacts")
.network(True)
.build()
)
async with console:
result = await console.exec(["python", "-c", "import matplotlib; print(matplotlib.__version__)"])
print(result.stdout.decode(), end="")
asyncio.run(main())

Besides exec, a console can read and write files in the VM.

For more information, see the virtx README.