Foundations
The API contract
One resource-oriented REST contract for every VM on every OS, reached the same way from the CLI, MCP and the socket.
The FlashVMM API contract is a resource-oriented REST interface, described in OpenAPI 3.1, that every flashvm process serves for its one VM under /v1/flashvm, with identical request bodies, defaults and typed error codes on Linux, macOS and Windows.
The API is strict CRUD with no verbs: an action is either a state change (PATCH) or a sub-resource (a noun). Pause is a state, a snapshot is a member of a collection, and restore is the create call with a different source. The request bodies, validators and the error catalog live in one shared crate, flash-contract, so a field or a default reaches all three operating systems at once. The flash CLI and the flash-mcp server send exactly these requests.
Key facts
| Runs on | Linux, macOS and Windows, one contract |
|---|---|
| Interfaces | CLI flash, 46 commands · MCP flash-mcp, 21 tools · REST 34 resources, 59 operations |
| Transport | HTTP/1.1 over the VM's own Unix socket (Linux, macOS) or named pipe (Windows) |
| Root | /v1/flashvm |
| Specification | OpenAPI 3.1, checked against the live binary on every build: every routed path is specified and every specified method answers |
| Errors | {"error": code, "message": text, "detail": json}, each code with exactly one HTTP status |
| Streams | Server-Sent Events for events, logs, metrics, connections and exec output |
How it works
Resources
The VM is /v1/flashvm; its parts are sub-resources: cpu, memory, memory/balloon, memory/mem, disk, limits, nics/{nic_index}, secret-proxies/{proxy_name}, share, source, snapshots/{snapshot_id}, metrics, logs, events, workload, version, and the guest channels guest/execs, guest/files, guest/requests and guest/messages.
Create is asynchronous
PUT /v1/flashvm answers 202 with an operation id; GET /v1/flashvm/operations/{operation_id} reports pending, done or failed, and /v1/flashvm/events streams the lifecycle. The source is a tagged union: {"type": "bundle"}, {"type": "snapshot"} or {"type": "snapshot_url", "url", "total"}. Snapshot capture is asynchronous the same way.
State
GET /v1/flashvm returns state (creating, starting, running, paused, exited, failed, terminated, parked) and always serializes entry_started and guest_ready, including false. A counter the host could not read is omitted rather than reported as zero, so a zero and an absent value stay distinct.
One contract, three servers
Wire shapes are defined once in flash-contract and re-exported by each OS's own contract crate; what differs per OS is the backend capability value and the transport. A test scans all three servers and fails when a code is emitted with a status other than the catalog's. Fleet services follow the same style: warm pools at /v1/vm-pools, sleeping VMs at /v1/host/sleep-images, claims at PUT /v1/flashvm/workload. See architecture and MCP.
Interfaces
CLI
flash pause web --max-ms 5000
flash resume web
flash set web --cpu-millis 500
flash snapshots web ls
MCP
flash_api(vm_id: "web", method: "PATCH", path: "/v1/flashvm", body: {"state": "paused", "max_ms": 5000})
flash_api(vm_id: "web", method: "PATCH", path: "/v1/flashvm", body: {"state": "running"})
flash_resource(vm_id: "web", resource: "operation", id: "op-1")
flash_resource(vm_id: "web", resource: "snapshots")
REST
PATCH /v1/flashvm {"state": "paused", "max_ms": 5000}
PATCH /v1/flashvm {"state": "running"}
GET /v1/flashvm/operations/{operation_id}
GET /v1/flashvm/snapshots
Typed refusals an agent should handle: 400 malformed_body for unparseable JSON; 422 invalid_body for a valid body of the wrong shape; 409 already_exists for a second create; 404 unknown_resource, unknown_nic, snapshot_not_found and unknown_operation; 409 vm_gone once the VM has exited; 503 no_guest_handler for guest HTTP on a VM started without --http-port; 422 mem_not_attached for memory/mem on a VM without a virtio-mem region.
Guarantees
- The spec is the build. Every routed path is in the OpenAPI document and every documented method answers on a live binary.
- One meaning per error. Each code maps to exactly one HTTP status on every OS.
- Nouns, not verbs. Every action is a create, read, state change or delete on a named resource.
- Same requests from every surface. CLI, MCP and direct REST send identical bodies to the same socket.