Deploy a Virtual Machine
deploy_virtual_machineDeploy a virtual machine onto Cycle. Prefer containers (deploy_application) for ordinary workloads; choose a VM only for hard isolation requirements, a custom OS or kernel (custom modules, non-Linux), or legacy software that cannot be containerized.
Platform rules this tool applies or checks:
The environment's cluster must contain a hypervisor-capable server. list_servers reports 'virtualization' per server; the response notes when no live server in the cluster confirms it. When hardware has to be provisioned for VMs, get_deployable_server_models reports 'hypervisor' per model (and takes hypervisor_only).
Image: exactly one of base_image or image_url. Call with NEITHER to fetch the live base-image catalogue (version identifiers, supported/UEFI flags) without deploying — do that first unless the user named an exact image; prefer versions marked supported. iPXE and external-volume image sources are not exposed here (a 'base' volume backed by a SAN volume is a different thing and IS supported).
Resources are explicit: ram is required, plus exactly one of cores or cpu_pin.
Storage: volumes MUST include the boot volume, identifier 'base'; creates without one are refused. Other volumes attach as RAW BLOCK DEVICES the guest must partition, format, and mount — remind the user.
Access: Cycle generates a root password at create. It is returned here but retrievable for only ~10 minutes, so relay it to the user promptly (afterwards reconfigure_virtual_machine sets a new one). SSH keys attach at provision time: ssh_keys references existing environment-scoped keys, new_ssh_keys creates and attaches them. Serial-over-SSH console access needs no VM networking: get_vm_console_access mints credentials for the user's own interactive session, and run_vm_command runs a single command and returns its output (in-guest setup like partitioning a volume goes through it).
Networking follows the container conventions: IPv6-ONLY private network, hostname defaults to the identifier, public defaults to 'disable', ports map like '443:443'. Point a domain at the VM afterwards with manage_dns_record (records can link to VMs).
Placement: constraints.node.tags.all/.any restricts which tagged servers may host the VM — same tag model as deploy_application; useful when only some servers are hypervisor-capable.
Workflow:
If the user hasn't picked an image, call with no base_image/image_url to list the base images.
Call with preview:true — returns the exact create request (read-only lookups only; nothing is created) to confirm with the user. Never create without explicit confirmation.
Call again without preview. The VM is created and, unless start:false, started. The first boot downloads the disk image and can outlast wait_seconds; the job keeps running on Cycle (check list_virtual_machines or get_jobs).
Retries are safe: identifier (default: slug of name) is the idempotency key — a repeat call refuses to create a duplicate and reports the existing VM. Pass a fresh identifier to deliberately create another alongside it.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ram | No | RAM limit, e.g. '2G'. At least 512M, less than 65G. | |
| name | No | Name for the virtual machine. Required except when listing base images. | |
| cores | No | Number of vCPU cores (1-32). | |
| ports | No | Port mappings like '443:443'. | |
| start | No | Start the VM right after creation (default). false leaves it stopped for cycle_control_virtual_machine. | |
| public | No | Public network access. Defaults to 'disable'. | |
| context | No | Why are you calling this tool? Briefly describe the user's goal. | |
| cpu_pin | No | Pin the VM to specific host cores/ranges, e.g. '0-3' ('x' = the host's max core). | |
| preview | No | Return the exact create request and make NO changes. Always run this first and confirm with the user. | |
| volumes | No | Volumes. Must include the boot volume, e.g. {identifier: 'base', size: '10G'}. | |
| hostname | No | Private network hostname. Defaults to the identifier. | |
| ssh_keys | No | Existing VM SSH keys to attach, by name or 24-char hex ID. Keys are environment-scoped. | |
| image_url | No | URL of a custom disk image to boot from. | |
| os_flavor | No | Guest OS flavor for platform preconfiguration. 'windows' adds virtio-win drivers and mounts a drive of provisioning scripts (github.com/cycleplatform/windows-vm-utils) because Windows lacks cloud-init — tell the user to run them for network setup inside the guest. | |
| base_image | No | Cycle base-image VERSION identifier from the catalogue this tool returns when called with no image. | |
| identifier | No | Identifier slug and idempotency key; defaults to a slug of name. | |
| constraints | No | Restrict which tagged servers may host this VM (tags live on servers). Confirm tags with list_servers first. | |
| environment | No | Target environment (must already exist and be live). Required except when listing base images. | |
| allocate_ram | No | Preallocate the RAM instead of growing on demand. | |
| new_ssh_keys | No | SSH keys to create in the environment from user-supplied public keys, then attach. | |
| wait_seconds | No | Max seconds to wait on the start job (default 60). 0 submits and returns immediately. | |
| allocate_cores | No | Reserve the cores exclusively for this VM. Only with cores. | |
| conversation_id | No | Conversation tracking id. Omit on your first tool call; every result then includes a conversation_id line — pass that exact value on all later calls in this conversation. |