> For the complete documentation index, see [llms.txt](https://firestonevm.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://firestonevm.gitbook.io/docs/api-reference/machines.md).

# Machines

Machine desired state, lifecycle, logs, and generated VMM config.

## List machines

> Returns the same summaries as the CLI list action. Request bodies and undocumented query fields are ignored.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines":{"get":{"tags":["Machines"],"operationId":"listMachines","summary":"List machines","description":"Returns the same summaries as the CLI list action. Request bodies and undocumented query fields are ignored.","responses":{"200":{"description":"Machine summaries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineSummaryList"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}}}}},"components":{"schemas":{"MachineSummaryList":{"type":"array","items":{"$ref":"#/components/schemas/MachineSummary"}},"MachineSummary":{"type":"object","properties":{"name":{"type":"string","minLength":1},"status":{"type":"string","enum":["created","starting","running","running!","running (unsupervised)","running! (unsupervised)","stopping","stopped","failed"]},"image":{"type":"string"},"cpus":{"type":"integer","minimum":1,"maximum":255},"memory":{"$ref":"#/components/schemas/MemorySize"},"uptime":{"anyOf":[{"type":"string","pattern":"^[0-9]+[smhd]$"},{"type":"null"}]},"forwards":{"type":"array","items":{"type":"string"}},"forwards_pending":{"type":"boolean","description":"Spec forwards differ from the forwards this running machine applied at spawn. Always false unless the machine is running; passt applies the new set on the next start."}},"additionalProperties":false,"required":["name","status","image","cpus","memory","uptime","forwards","forwards_pending"]},"MemorySize":{"type":"string","pattern":"^(?:(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)M|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)G)$","description":"Canonical effective memory size, at least 128 MiB."},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}
```

## Create a machine

> Layers the supplied MachineSpecPatch over the router's snapshot of global create defaults, validates the resulting effective spec, and dispatches the shared create action. Both name and spec are required; spec may be {}.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines":{"post":{"tags":["Machines"],"operationId":"createMachine","summary":"Create a machine","description":"Layers the supplied MachineSpecPatch over the router's snapshot of global create defaults, validates the resulting effective spec, and dispatches the shared create action. Both name and spec are required; spec may be {}.","responses":{"201":{"description":"Created machine and effective state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineRecord"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"requestBody":{"required":true,"description":"Exactly one JSON object. Unknown fields are rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMachineRequest"}}}}}}},"components":{"schemas":{"MachineRecord":{"type":"object","properties":{"name":{"type":"string","minLength":1},"spec":{"$ref":"#/components/schemas/MachineSpec"},"state":{"$ref":"#/components/schemas/MachineState"}},"additionalProperties":false,"required":["name","spec","state"]},"MachineSpec":{"type":"object","properties":{"image":{"$ref":"#/components/schemas/MachineImageRef"},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":"integer","minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Opt-in vCPU hotplug ceiling. Null means no headroom: max_vcpus equals cpus and a running machine cannot gain vCPUs."},"memory":{"$ref":"#/components/schemas/MemorySize"},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySize"},{"type":"null"}],"description":"Opt-in memory hotplug ceiling. Null means no headroom: the VmConfig carries no hotplug_size and a running machine cannot gain memory."},"disk":{"$ref":"#/components/schemas/ByteSize"},"user":{"type":"string","pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"$ref":"#/components/schemas/NetworkSpec"},"mount":{"type":"array","items":{"$ref":"#/components/schemas/MountSpec"},"maxItems":16},"cloud_init":{"$ref":"#/components/schemas/CloudInitSpec"},"vmm":{"$ref":"#/components/schemas/VmmSpec"}},"additionalProperties":false,"required":["image","arch","cpus","cpus_max","memory","memory_max","disk","user","network","mount","cloud_init","vmm"],"description":"Effective machine spec returned by Firestone. Optional values are emitted as JSON null; all top-level properties are present."},"MachineImageRef":{"allOf":[{"$ref":"#/components/schemas/ImageRef"},{"pattern":"\\S"}],"description":"Machine image reference containing at least one non-whitespace character."},"ImageRef":{"type":"string","minLength":1,"description":"Catalog reference, strict HTTPS URL, or local image path. Pull resolution performs source-specific validation."},"Architecture":{"type":"string","enum":["x86_64","aarch64"],"description":"CPU architecture accepted by the shared machine model."},"MemorySize":{"type":"string","pattern":"^(?:(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)M|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)G)$","description":"Canonical effective memory size, at least 128 MiB."},"ByteSize":{"type":"string","pattern":"^[0-9]+[MG]$","description":"Canonical whole-MiB or whole-GiB size emitted by Firestone."},"NetworkSpec":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/NetMode"},"forward":{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},"tap":{"anyOf":[{"type":"string"},{"type":"null"}]},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"required":["mode","forward","tap","mac"],"allOf":[{"if":{"properties":{"mode":{"const":"tap"}},"required":["mode"]},"then":{"properties":{"tap":{"type":"string","minLength":1,"maxLength":15,"not":{"enum":[".",".."]},"pattern":"^[^/\\u0000]+$"}},"required":["tap"]}}]},"NetMode":{"type":"string","enum":["passt","tap","none"]},"PortForward":{"type":"string","minLength":3,"description":"[proto:][bind:]HOST:GUEST. Protocol is tcp (default) or udp; port/range endpoints are 1 through 65535 and host/guest ranges have equal lengths."},"MacAddress":{"type":"string","pattern":"^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$"},"MountSpec":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean"},"tag":{"anyOf":[{"type":"string","minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"},{"type":"null"}]}},"additionalProperties":false,"required":["host","guest","readonly","tag"]},"Path":{"type":"string","description":"UTF-8 filesystem path."},"GuestMountPath":{"type":"string","minLength":2,"maxLength":4095,"pattern":"^/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+)(?:/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+))*$","description":"Canonical absolute non-root guest path with no dot components, duplicate separators, trailing slash, NUL, or ASCII control characters. Linux byte and component limits are validated after decoding."},"CloudInitSpec":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"],"description":"Inline user part, at most 32 KiB. Mutually exclusive with user_data."},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"type":"array","items":{"$ref":"#/components/schemas/Path"}},"ssh_authorized_keys":{"type":"array","items":{"type":"string"},"description":"Inline OpenSSH public keys, deduplicated together with ssh_keys."},"password":{"type":["string","null"],"description":"Plaintext guest password for user, 1 to 256 bytes without control characters."},"ssh_pwauth":{"type":"boolean"},"provisioning":{"type":"boolean"}},"additionalProperties":false,"required":["user_data","user_data_inline","network_config","ssh_keys","ssh_authorized_keys","password","ssh_pwauth","provisioning"]},"VmmSpec":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"$ref":"#/components/schemas/Firmware"},"extra_args":{"type":"array","items":{"type":"string"}},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"required":["binary","firmware","extra_args","config_overlay"]},"Firmware":{"type":"string","minLength":1,"description":"auto, rhf, edk2, or a non-empty UTF-8 firmware path."},"JsonObject":{"type":"object","additionalProperties":true,"description":"JSON object; nested null values retain RFC 7396 deletion semantics."},"MachineState":{"type":"object","properties":{"version":{"type":"integer","const":1},"status":{"$ref":"#/components/schemas/MachineStatus"},"image":{"$ref":"#/components/schemas/StateImage"},"mac":{"anyOf":[{"type":"string","description":"Persisted state text; state serde does not re-parse it as MacAddr."},{"type":"null"}]},"cid":{"type":"integer","minimum":0,"maximum":4294967295,"description":"Production-created machines use 3; state serde accepts any u32 and VmConfig generation rejects non-3 values."},"instance_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"shim_pid":{"anyOf":[{"type":"integer","minimum":1,"maximum":4294967295},{"type":"null"}]},"vmm_pid":{"anyOf":[{"type":"integer","minimum":1,"maximum":4294967295},{"type":"null"}]},"sidecar_pids":{"type":"object","additionalProperties":{"type":"integer","minimum":1,"maximum":4294967295}},"runtime_dir":{"$ref":"#/components/schemas/Path"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"forwards":{"type":"array","items":{"type":"string"}},"degraded":{"type":"array","items":{"type":"string"}},"last_exit":{"anyOf":[{"$ref":"#/components/schemas/LastExit"},{"type":"null"}]}},"additionalProperties":false,"required":["version","status","image","mac","cid","instance_id","shim_pid","vmm_pid","sidecar_pids","runtime_dir","started_at","forwards","degraded","last_exit"]},"MachineStatus":{"type":"string","enum":["created","starting","running","stopping","stopped","failed"]},"StateImage":{"type":"object","properties":{"ref":{"type":"string","minLength":1},"id":{"anyOf":[{"type":"string","minLength":1,"description":"Pinned image identifier as stored in state; state serde does not enforce the image-store ID grammar."},{"type":"null"}]},"sha256":{"anyOf":[{"type":"string","minLength":1,"description":"Pinned source digest as stored in state; state serde does not enforce digest syntax."},{"type":"null"}]}},"additionalProperties":false,"required":["ref","id","sha256"],"oneOf":[{"properties":{"id":{"type":"null"},"sha256":{"type":"null"}}},{"properties":{"id":{"type":"string","minLength":1},"sha256":{"type":"string","minLength":1}}}]},"LastExit":{"type":"object","properties":{"at":{"type":"string"},"code":{"anyOf":[{"type":"integer","minimum":-2147483648,"maximum":2147483647},{"type":"null"}]},"signal":{"anyOf":[{"type":"integer","minimum":-2147483648,"maximum":2147483647},{"type":"null"}]},"reason":{"type":"string","minLength":1,"description":"Known values include guest shutdown, stale, and host reboot; concrete failure diagnostics are also preserved."}},"additionalProperties":false,"required":["at","code","signal","reason"],"description":"code and signal cannot both be non-null.","oneOf":[{"properties":{"code":{"type":"integer"},"signal":{"type":"null"}}},{"properties":{"code":{"type":"null"},"signal":{"type":"integer"}}},{"properties":{"code":{"type":"null"},"signal":{"type":"null"}}}]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"CreateMachineRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$","description":"One non-empty Unix path component without control characters."},"spec":{"$ref":"#/components/schemas/MachineSpecPatch"}},"additionalProperties":false,"required":["name","spec"]},"MachineSpecPatch":{"type":"object","properties":{"clear":{"type":"array","items":{"$ref":"#/components/schemas/SpecClear"},"uniqueItems":true},"image":{"anyOf":[{"$ref":"#/components/schemas/MachineImageRef"},{"type":"null"}]},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":["integer","null"],"minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Optional vCPU hotplug ceiling; must be at least cpus."},"memory":{"anyOf":[{"$ref":"#/components/schemas/MemorySizeInput"},{"type":"null"}]},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySizeInput"},{"type":"null"}],"description":"Optional memory hotplug ceiling; must be at least memory."},"disk":{"anyOf":[{"$ref":"#/components/schemas/ByteSizeInput"},{"type":"null"}]},"user":{"type":["string","null"],"pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"anyOf":[{"$ref":"#/components/schemas/NetworkSpecPatch"},{"type":"null"}]},"mount":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/MountSpecInput"},"maxItems":16},{"type":"null"}]},"cloud_init":{"anyOf":[{"$ref":"#/components/schemas/CloudInitSpecPatch"},{"type":"null"}]},"vmm":{"anyOf":[{"$ref":"#/components/schemas/VmmSpecPatch"},{"type":"null"}]}},"additionalProperties":false,"description":"Sparse layer used by create and PATCH. Every property is optional. Null Option-backed values are treated as absent, not as clear operations. clear is the only way to clear optional or vector leaves; a layer cannot set and clear the same leaf.","allOf":[{"not":{"properties":{"clear":{"contains":{"const":"arch"}},"arch":{"not":{"type":"null"}}},"required":["clear","arch"]}},{"not":{"properties":{"clear":{"contains":{"const":"network.forward"}},"network":{"type":"object","properties":{"forward":{"not":{"type":"null"}}},"required":["forward"]}},"required":["clear","network"]}},{"not":{"properties":{"clear":{"contains":{"const":"network.tap"}},"network":{"type":"object","properties":{"tap":{"not":{"type":"null"}}},"required":["tap"]}},"required":["clear","network"]}},{"not":{"properties":{"clear":{"contains":{"const":"network.mac"}},"network":{"type":"object","properties":{"mac":{"not":{"type":"null"}}},"required":["mac"]}},"required":["clear","network"]}},{"not":{"properties":{"clear":{"contains":{"const":"mount"}},"mount":{"not":{"type":"null"}}},"required":["clear","mount"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.user_data"}},"cloud_init":{"type":"object","properties":{"user_data":{"not":{"type":"null"}}},"required":["user_data"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.user_data_inline"}},"cloud_init":{"type":"object","properties":{"user_data_inline":{"not":{"type":"null"}}},"required":["user_data_inline"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.network_config"}},"cloud_init":{"type":"object","properties":{"network_config":{"not":{"type":"null"}}},"required":["network_config"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.ssh_keys"}},"cloud_init":{"type":"object","properties":{"ssh_keys":{"not":{"type":"null"}}},"required":["ssh_keys"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.password"}},"cloud_init":{"type":"object","properties":{"password":{"not":{"type":"null"}}},"required":["password"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.ssh_authorized_keys"}},"cloud_init":{"type":"object","properties":{"ssh_authorized_keys":{"not":{"type":"null"}}},"required":["ssh_authorized_keys"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"vmm.binary"}},"vmm":{"type":"object","properties":{"binary":{"not":{"type":"null"}}},"required":["binary"]}},"required":["clear","vmm"]}},{"not":{"properties":{"clear":{"contains":{"const":"vmm.extra_args"}},"vmm":{"type":"object","properties":{"extra_args":{"not":{"type":"null"}}},"required":["extra_args"]}},"required":["clear","vmm"]}},{"not":{"properties":{"clear":{"contains":{"const":"vmm.config_overlay"}},"vmm":{"type":"object","properties":{"config_overlay":{"not":{"type":"null"}}},"required":["config_overlay"]}},"required":["clear","vmm"]}}]},"SpecClear":{"type":"string","enum":["arch","network.forward","network.tap","network.mac","mount","cloud_init.user_data","cloud_init.user_data_inline","cloud_init.network_config","cloud_init.ssh_keys","cloud_init.ssh_authorized_keys","cloud_init.password","vmm.binary","vmm.extra_args","vmm.config_overlay","cpus_max","memory_max"]},"MemorySizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)[Mm]?\\s*$","description":"Whole MiB from 128 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)[Gg]\\s*$","description":"Whole GiB from 1 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":128,"maximum":17592186044415,"description":"Whole MiB."}],"description":"Machine memory must resolve to at least 128 MiB and fit in u64 bytes."},"ByteSizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:0|(?:[1-9][0-9]{0,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415))[Mm]?\\s*$","description":"Whole MiB with no suffix or M/m, from 0 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:0|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183))[Gg]\\s*$","description":"Whole GiB with G/g, from 0 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":0,"maximum":17592186044415,"description":"Whole MiB."}]},"NetworkSpecPatch":{"type":"object","properties":{"mode":{"anyOf":[{"$ref":"#/components/schemas/NetMode"},{"type":"null"}]},"forward":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},{"type":"null"}]},"tap":{"type":["string","null"],"description":"Empty text is accepted while inactive; the effective value is validated as a Linux TAP name when mode is tap."},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"description":"Sparse network layer. Missing or null properties make no change; use the root clear list to remove an effective value."},"MountSpecInput":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean","default":false},"tag":{"type":["string","null"],"minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"}},"additionalProperties":false,"required":["host","guest"],"description":"One virtio-fs mount. host and guest are required; readonly defaults to false and tag defaults to a generated shareN value when omitted."},"CloudInitSpecPatch":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"]},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/Path"}},{"type":"null"}]},"ssh_authorized_keys":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"password":{"type":["string","null"]},"ssh_pwauth":{"type":["boolean","null"]},"provisioning":{"type":["boolean","null"]}},"additionalProperties":false,"description":"Sparse cloud-init layer. Missing or null properties make no change."},"VmmSpecPatch":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"anyOf":[{"$ref":"#/components/schemas/Firmware"},{"type":"null"}]},"extra_args":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"description":"Sparse VMM layer. config_overlay must be an object when non-null."}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}
```

## Get one machine

> Returns the effective spec, reconciled state, and nullable live supervision. Request bodies and undocumented query fields are ignored.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}":{"get":{"tags":["Machines"],"operationId":"getMachine","summary":"Get one machine","description":"Returns the effective spec, reconciled state, and nullable live supervision. Request bodies and undocumented query fields are ignored.","responses":{"200":{"description":"Machine view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineView"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"MachineView":{"type":"object","properties":{"spec":{"$ref":"#/components/schemas/MachineSpec"},"state":{"$ref":"#/components/schemas/MachineState"},"supervision":{"anyOf":[{"$ref":"#/components/schemas/Supervision"},{"type":"null"}]},"forwards_pending":{"type":"boolean","description":"Spec forwards differ from the forwards this running machine applied at spawn. Always false unless the machine is running; passt applies the new set on the next start."},"image_pending":{"type":"boolean","description":"The spec's image reference, resolved through the catalog by the §8.2 rules, names an image other than the one this running machine booted. Catalog aliases and default references resolve first, so a machine created as 'ubuntu' and running 'ubuntu:24.04' is not pending. Always false unless the machine is running."}},"additionalProperties":false,"required":["spec","state","supervision","forwards_pending","image_pending"]},"MachineSpec":{"type":"object","properties":{"image":{"$ref":"#/components/schemas/MachineImageRef"},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":"integer","minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Opt-in vCPU hotplug ceiling. Null means no headroom: max_vcpus equals cpus and a running machine cannot gain vCPUs."},"memory":{"$ref":"#/components/schemas/MemorySize"},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySize"},{"type":"null"}],"description":"Opt-in memory hotplug ceiling. Null means no headroom: the VmConfig carries no hotplug_size and a running machine cannot gain memory."},"disk":{"$ref":"#/components/schemas/ByteSize"},"user":{"type":"string","pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"$ref":"#/components/schemas/NetworkSpec"},"mount":{"type":"array","items":{"$ref":"#/components/schemas/MountSpec"},"maxItems":16},"cloud_init":{"$ref":"#/components/schemas/CloudInitSpec"},"vmm":{"$ref":"#/components/schemas/VmmSpec"}},"additionalProperties":false,"required":["image","arch","cpus","cpus_max","memory","memory_max","disk","user","network","mount","cloud_init","vmm"],"description":"Effective machine spec returned by Firestone. Optional values are emitted as JSON null; all top-level properties are present."},"MachineImageRef":{"allOf":[{"$ref":"#/components/schemas/ImageRef"},{"pattern":"\\S"}],"description":"Machine image reference containing at least one non-whitespace character."},"ImageRef":{"type":"string","minLength":1,"description":"Catalog reference, strict HTTPS URL, or local image path. Pull resolution performs source-specific validation."},"Architecture":{"type":"string","enum":["x86_64","aarch64"],"description":"CPU architecture accepted by the shared machine model."},"MemorySize":{"type":"string","pattern":"^(?:(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)M|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)G)$","description":"Canonical effective memory size, at least 128 MiB."},"ByteSize":{"type":"string","pattern":"^[0-9]+[MG]$","description":"Canonical whole-MiB or whole-GiB size emitted by Firestone."},"NetworkSpec":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/NetMode"},"forward":{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},"tap":{"anyOf":[{"type":"string"},{"type":"null"}]},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"required":["mode","forward","tap","mac"],"allOf":[{"if":{"properties":{"mode":{"const":"tap"}},"required":["mode"]},"then":{"properties":{"tap":{"type":"string","minLength":1,"maxLength":15,"not":{"enum":[".",".."]},"pattern":"^[^/\\u0000]+$"}},"required":["tap"]}}]},"NetMode":{"type":"string","enum":["passt","tap","none"]},"PortForward":{"type":"string","minLength":3,"description":"[proto:][bind:]HOST:GUEST. Protocol is tcp (default) or udp; port/range endpoints are 1 through 65535 and host/guest ranges have equal lengths."},"MacAddress":{"type":"string","pattern":"^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$"},"MountSpec":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean"},"tag":{"anyOf":[{"type":"string","minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"},{"type":"null"}]}},"additionalProperties":false,"required":["host","guest","readonly","tag"]},"Path":{"type":"string","description":"UTF-8 filesystem path."},"GuestMountPath":{"type":"string","minLength":2,"maxLength":4095,"pattern":"^/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+)(?:/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+))*$","description":"Canonical absolute non-root guest path with no dot components, duplicate separators, trailing slash, NUL, or ASCII control characters. Linux byte and component limits are validated after decoding."},"CloudInitSpec":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"],"description":"Inline user part, at most 32 KiB. Mutually exclusive with user_data."},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"type":"array","items":{"$ref":"#/components/schemas/Path"}},"ssh_authorized_keys":{"type":"array","items":{"type":"string"},"description":"Inline OpenSSH public keys, deduplicated together with ssh_keys."},"password":{"type":["string","null"],"description":"Plaintext guest password for user, 1 to 256 bytes without control characters."},"ssh_pwauth":{"type":"boolean"},"provisioning":{"type":"boolean"}},"additionalProperties":false,"required":["user_data","user_data_inline","network_config","ssh_keys","ssh_authorized_keys","password","ssh_pwauth","provisioning"]},"VmmSpec":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"$ref":"#/components/schemas/Firmware"},"extra_args":{"type":"array","items":{"type":"string"}},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"required":["binary","firmware","extra_args","config_overlay"]},"Firmware":{"type":"string","minLength":1,"description":"auto, rhf, edk2, or a non-empty UTF-8 firmware path."},"JsonObject":{"type":"object","additionalProperties":true,"description":"JSON object; nested null values retain RFC 7396 deletion semantics."},"MachineState":{"type":"object","properties":{"version":{"type":"integer","const":1},"status":{"$ref":"#/components/schemas/MachineStatus"},"image":{"$ref":"#/components/schemas/StateImage"},"mac":{"anyOf":[{"type":"string","description":"Persisted state text; state serde does not re-parse it as MacAddr."},{"type":"null"}]},"cid":{"type":"integer","minimum":0,"maximum":4294967295,"description":"Production-created machines use 3; state serde accepts any u32 and VmConfig generation rejects non-3 values."},"instance_id":{"anyOf":[{"type":"string"},{"type":"null"}]},"shim_pid":{"anyOf":[{"type":"integer","minimum":1,"maximum":4294967295},{"type":"null"}]},"vmm_pid":{"anyOf":[{"type":"integer","minimum":1,"maximum":4294967295},{"type":"null"}]},"sidecar_pids":{"type":"object","additionalProperties":{"type":"integer","minimum":1,"maximum":4294967295}},"runtime_dir":{"$ref":"#/components/schemas/Path"},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}]},"forwards":{"type":"array","items":{"type":"string"}},"degraded":{"type":"array","items":{"type":"string"}},"last_exit":{"anyOf":[{"$ref":"#/components/schemas/LastExit"},{"type":"null"}]}},"additionalProperties":false,"required":["version","status","image","mac","cid","instance_id","shim_pid","vmm_pid","sidecar_pids","runtime_dir","started_at","forwards","degraded","last_exit"]},"MachineStatus":{"type":"string","enum":["created","starting","running","stopping","stopped","failed"]},"StateImage":{"type":"object","properties":{"ref":{"type":"string","minLength":1},"id":{"anyOf":[{"type":"string","minLength":1,"description":"Pinned image identifier as stored in state; state serde does not enforce the image-store ID grammar."},{"type":"null"}]},"sha256":{"anyOf":[{"type":"string","minLength":1,"description":"Pinned source digest as stored in state; state serde does not enforce digest syntax."},{"type":"null"}]}},"additionalProperties":false,"required":["ref","id","sha256"],"oneOf":[{"properties":{"id":{"type":"null"},"sha256":{"type":"null"}}},{"properties":{"id":{"type":"string","minLength":1},"sha256":{"type":"string","minLength":1}}}]},"LastExit":{"type":"object","properties":{"at":{"type":"string"},"code":{"anyOf":[{"type":"integer","minimum":-2147483648,"maximum":2147483647},{"type":"null"}]},"signal":{"anyOf":[{"type":"integer","minimum":-2147483648,"maximum":2147483647},{"type":"null"}]},"reason":{"type":"string","minLength":1,"description":"Known values include guest shutdown, stale, and host reboot; concrete failure diagnostics are also preserved."}},"additionalProperties":false,"required":["at","code","signal","reason"],"description":"code and signal cannot both be non-null.","oneOf":[{"properties":{"code":{"type":"integer"},"signal":{"type":"null"}}},{"properties":{"code":{"type":"null"},"signal":{"type":"integer"}}},{"properties":{"code":{"type":"null"},"signal":{"type":"null"}}}]},"Supervision":{"type":"string","enum":["supervised","unsupervised"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Replace a machine spec

> Accepts MachineSpec directly. Every property is input-optional because serde fills omitted properties from built-in MachineSpec defaults; this PUT therefore does not require clients to send every property.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}":{"put":{"tags":["Machines"],"operationId":"replaceMachineSpec","summary":"Replace a machine spec","description":"Accepts MachineSpec directly. Every property is input-optional because serde fills omitted properties from built-in MachineSpec defaults; this PUT therefore does not require clients to send every property.","responses":{"200":{"description":"Effective saved spec and all non-fatal warnings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}],"requestBody":{"required":true,"description":"A JSON object is required; {} resets the effective spec to built-in defaults. Unknown fields are rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineSpecInput"}}}}}}},"components":{"schemas":{"SpecResult":{"type":"object","properties":{"spec":{"$ref":"#/components/schemas/MachineSpec"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/SpecWarning"}}},"additionalProperties":false,"required":["spec","warnings"]},"MachineSpec":{"type":"object","properties":{"image":{"$ref":"#/components/schemas/MachineImageRef"},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":"integer","minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Opt-in vCPU hotplug ceiling. Null means no headroom: max_vcpus equals cpus and a running machine cannot gain vCPUs."},"memory":{"$ref":"#/components/schemas/MemorySize"},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySize"},{"type":"null"}],"description":"Opt-in memory hotplug ceiling. Null means no headroom: the VmConfig carries no hotplug_size and a running machine cannot gain memory."},"disk":{"$ref":"#/components/schemas/ByteSize"},"user":{"type":"string","pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"$ref":"#/components/schemas/NetworkSpec"},"mount":{"type":"array","items":{"$ref":"#/components/schemas/MountSpec"},"maxItems":16},"cloud_init":{"$ref":"#/components/schemas/CloudInitSpec"},"vmm":{"$ref":"#/components/schemas/VmmSpec"}},"additionalProperties":false,"required":["image","arch","cpus","cpus_max","memory","memory_max","disk","user","network","mount","cloud_init","vmm"],"description":"Effective machine spec returned by Firestone. Optional values are emitted as JSON null; all top-level properties are present."},"MachineImageRef":{"allOf":[{"$ref":"#/components/schemas/ImageRef"},{"pattern":"\\S"}],"description":"Machine image reference containing at least one non-whitespace character."},"ImageRef":{"type":"string","minLength":1,"description":"Catalog reference, strict HTTPS URL, or local image path. Pull resolution performs source-specific validation."},"Architecture":{"type":"string","enum":["x86_64","aarch64"],"description":"CPU architecture accepted by the shared machine model."},"MemorySize":{"type":"string","pattern":"^(?:(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)M|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)G)$","description":"Canonical effective memory size, at least 128 MiB."},"ByteSize":{"type":"string","pattern":"^[0-9]+[MG]$","description":"Canonical whole-MiB or whole-GiB size emitted by Firestone."},"NetworkSpec":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/NetMode"},"forward":{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},"tap":{"anyOf":[{"type":"string"},{"type":"null"}]},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"required":["mode","forward","tap","mac"],"allOf":[{"if":{"properties":{"mode":{"const":"tap"}},"required":["mode"]},"then":{"properties":{"tap":{"type":"string","minLength":1,"maxLength":15,"not":{"enum":[".",".."]},"pattern":"^[^/\\u0000]+$"}},"required":["tap"]}}]},"NetMode":{"type":"string","enum":["passt","tap","none"]},"PortForward":{"type":"string","minLength":3,"description":"[proto:][bind:]HOST:GUEST. Protocol is tcp (default) or udp; port/range endpoints are 1 through 65535 and host/guest ranges have equal lengths."},"MacAddress":{"type":"string","pattern":"^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$"},"MountSpec":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean"},"tag":{"anyOf":[{"type":"string","minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"},{"type":"null"}]}},"additionalProperties":false,"required":["host","guest","readonly","tag"]},"Path":{"type":"string","description":"UTF-8 filesystem path."},"GuestMountPath":{"type":"string","minLength":2,"maxLength":4095,"pattern":"^/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+)(?:/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+))*$","description":"Canonical absolute non-root guest path with no dot components, duplicate separators, trailing slash, NUL, or ASCII control characters. Linux byte and component limits are validated after decoding."},"CloudInitSpec":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"],"description":"Inline user part, at most 32 KiB. Mutually exclusive with user_data."},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"type":"array","items":{"$ref":"#/components/schemas/Path"}},"ssh_authorized_keys":{"type":"array","items":{"type":"string"},"description":"Inline OpenSSH public keys, deduplicated together with ssh_keys."},"password":{"type":["string","null"],"description":"Plaintext guest password for user, 1 to 256 bytes without control characters."},"ssh_pwauth":{"type":"boolean"},"provisioning":{"type":"boolean"}},"additionalProperties":false,"required":["user_data","user_data_inline","network_config","ssh_keys","ssh_authorized_keys","password","ssh_pwauth","provisioning"]},"VmmSpec":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"$ref":"#/components/schemas/Firmware"},"extra_args":{"type":"array","items":{"type":"string"}},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"required":["binary","firmware","extra_args","config_overlay"]},"Firmware":{"type":"string","minLength":1,"description":"auto, rhf, edk2, or a non-empty UTF-8 firmware path."},"JsonObject":{"type":"object","additionalProperties":true,"description":"JSON object; nested null values retain RFC 7396 deletion semantics."},"SpecWarning":{"type":"object","properties":{"key":{"type":"string"},"message":{"type":"string"}},"additionalProperties":false,"required":["key","message"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"MachineSpecInput":{"type":"object","properties":{"image":{"$ref":"#/components/schemas/MachineImageRef"},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":"integer","minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Optional vCPU hotplug ceiling; must be at least cpus."},"memory":{"$ref":"#/components/schemas/MemorySizeInput"},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySizeInput"},{"type":"null"}],"description":"Optional memory hotplug ceiling; must be at least memory."},"disk":{"$ref":"#/components/schemas/ByteSizeInput"},"user":{"type":"string","pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"$ref":"#/components/schemas/NetworkSpecInput"},"mount":{"type":"array","items":{"$ref":"#/components/schemas/MountSpecInput"},"maxItems":16},"cloud_init":{"$ref":"#/components/schemas/CloudInitSpecInput"},"vmm":{"$ref":"#/components/schemas/VmmSpecInput"}},"additionalProperties":false,"description":"Complete-spec input accepted by PUT. Because MachineSpec uses serde defaults, every property may be omitted and is filled from built-in defaults. Only arch, cpus_max and memory_max are Option-backed and accept JSON null. Unknown properties are rejected."},"MemorySizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)[Mm]?\\s*$","description":"Whole MiB from 128 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)[Gg]\\s*$","description":"Whole GiB from 1 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":128,"maximum":17592186044415,"description":"Whole MiB."}],"description":"Machine memory must resolve to at least 128 MiB and fit in u64 bytes."},"ByteSizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:0|(?:[1-9][0-9]{0,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415))[Mm]?\\s*$","description":"Whole MiB with no suffix or M/m, from 0 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:0|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183))[Gg]\\s*$","description":"Whole GiB with G/g, from 0 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":0,"maximum":17592186044415,"description":"Whole MiB."}]},"NetworkSpecInput":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/NetMode"},"forward":{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},"tap":{"type":["string","null"]},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"description":"All properties may be omitted and inherit NetworkSpec defaults. Only the Option-backed tap and mac properties accept JSON null.","allOf":[{"if":{"properties":{"mode":{"const":"tap"}},"required":["mode"]},"then":{"properties":{"tap":{"type":"string","minLength":1,"maxLength":15,"not":{"enum":[".",".."]},"pattern":"^[^/\\u0000]+$"}},"required":["tap"]}}]},"MountSpecInput":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean","default":false},"tag":{"type":["string","null"],"minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"}},"additionalProperties":false,"required":["host","guest"],"description":"One virtio-fs mount. host and guest are required; readonly defaults to false and tag defaults to a generated shareN value when omitted."},"CloudInitSpecInput":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"],"description":"Inline user part, at most 32 KiB. Mutually exclusive with user_data."},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"type":"array","items":{"$ref":"#/components/schemas/Path"}},"ssh_authorized_keys":{"type":"array","items":{"type":"string"},"description":"Inline OpenSSH public keys, deduplicated together with ssh_keys."},"password":{"type":["string","null"],"description":"Plaintext guest password for user, 1 to 256 bytes without control characters."},"ssh_pwauth":{"type":"boolean"},"provisioning":{"type":"boolean"}},"additionalProperties":false,"description":"All properties may be omitted and inherit CloudInitSpec defaults. Only user_data, user_data_inline, network_config and password accept JSON null."},"VmmSpecInput":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"$ref":"#/components/schemas/Firmware"},"extra_args":{"type":"array","items":{"type":"string"}},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"description":"All properties may be omitted and inherit VmmSpec defaults. binary and config_overlay accept JSON null; config_overlay must otherwise be an object."}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Delete a machine

> The request body is ignored. If removal emits no progress before Result, success is an empty 204. If a running machine must stop first, success is a 200 NDJSON stream by default or a 200 aggregate when Accept selects application/json.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}":{"delete":{"tags":["Machines"],"operationId":"deleteMachine","summary":"Delete a machine","description":"The request body is ignored. If removal emits no progress before Result, success is an empty 204. If a running machine must stop first, success is a 200 NDJSON stream by default or a 200 aggregate when Accept selects application/json.","responses":{"200":{"description":"Removal progress and typed terminal result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/RemoveMachineDispatchOutput"}}}},"204":{"description":"Machine removed without preceding progress. Empty body and no Content-Type header."},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"},{"$ref":"#/components/parameters/Force"}]}}},"components":{"schemas":{"RemoveMachineDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/RemoveMachineResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"RemoveMachineResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"rm"},"payload":{"$ref":"#/components/schemas/RemoveResult"}},"additionalProperties":false,"required":["type","action","payload"]},"RemoveResult":{"type":"object","properties":{"removed":{"type":"array","items":{"type":"string"}}},"additionalProperties":false,"required":["removed"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}},"Force":{"name":"force","in":"query","required":false,"description":"Defaults to false. Unknown, duplicate, or non-boolean query fields are rejected on force-query routes.","schema":{"type":"boolean","default":false}}}}}
```

## Patch a machine spec

> Applies the sparse MachineSpecPatch through the shared layering and path-provenance rules. Null patch properties mean no update; use clear for deletion.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}":{"patch":{"tags":["Machines"],"operationId":"patchMachineSpec","summary":"Patch a machine spec","description":"Applies the sparse MachineSpecPatch through the shared layering and path-provenance rules. Null patch properties mean no update; use clear for deletion.","responses":{"200":{"description":"Effective saved spec and all non-fatal warnings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpecResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}],"requestBody":{"required":true,"description":"A JSON object is required; {} is a valid no-op. Unknown fields are rejected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MachineSpecPatch"}}}}}}},"components":{"schemas":{"SpecResult":{"type":"object","properties":{"spec":{"$ref":"#/components/schemas/MachineSpec"},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/SpecWarning"}}},"additionalProperties":false,"required":["spec","warnings"]},"MachineSpec":{"type":"object","properties":{"image":{"$ref":"#/components/schemas/MachineImageRef"},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":"integer","minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Opt-in vCPU hotplug ceiling. Null means no headroom: max_vcpus equals cpus and a running machine cannot gain vCPUs."},"memory":{"$ref":"#/components/schemas/MemorySize"},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySize"},{"type":"null"}],"description":"Opt-in memory hotplug ceiling. Null means no headroom: the VmConfig carries no hotplug_size and a running machine cannot gain memory."},"disk":{"$ref":"#/components/schemas/ByteSize"},"user":{"type":"string","pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"$ref":"#/components/schemas/NetworkSpec"},"mount":{"type":"array","items":{"$ref":"#/components/schemas/MountSpec"},"maxItems":16},"cloud_init":{"$ref":"#/components/schemas/CloudInitSpec"},"vmm":{"$ref":"#/components/schemas/VmmSpec"}},"additionalProperties":false,"required":["image","arch","cpus","cpus_max","memory","memory_max","disk","user","network","mount","cloud_init","vmm"],"description":"Effective machine spec returned by Firestone. Optional values are emitted as JSON null; all top-level properties are present."},"MachineImageRef":{"allOf":[{"$ref":"#/components/schemas/ImageRef"},{"pattern":"\\S"}],"description":"Machine image reference containing at least one non-whitespace character."},"ImageRef":{"type":"string","minLength":1,"description":"Catalog reference, strict HTTPS URL, or local image path. Pull resolution performs source-specific validation."},"Architecture":{"type":"string","enum":["x86_64","aarch64"],"description":"CPU architecture accepted by the shared machine model."},"MemorySize":{"type":"string","pattern":"^(?:(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)M|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)G)$","description":"Canonical effective memory size, at least 128 MiB."},"ByteSize":{"type":"string","pattern":"^[0-9]+[MG]$","description":"Canonical whole-MiB or whole-GiB size emitted by Firestone."},"NetworkSpec":{"type":"object","properties":{"mode":{"$ref":"#/components/schemas/NetMode"},"forward":{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},"tap":{"anyOf":[{"type":"string"},{"type":"null"}]},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"required":["mode","forward","tap","mac"],"allOf":[{"if":{"properties":{"mode":{"const":"tap"}},"required":["mode"]},"then":{"properties":{"tap":{"type":"string","minLength":1,"maxLength":15,"not":{"enum":[".",".."]},"pattern":"^[^/\\u0000]+$"}},"required":["tap"]}}]},"NetMode":{"type":"string","enum":["passt","tap","none"]},"PortForward":{"type":"string","minLength":3,"description":"[proto:][bind:]HOST:GUEST. Protocol is tcp (default) or udp; port/range endpoints are 1 through 65535 and host/guest ranges have equal lengths."},"MacAddress":{"type":"string","pattern":"^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$"},"MountSpec":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean"},"tag":{"anyOf":[{"type":"string","minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"},{"type":"null"}]}},"additionalProperties":false,"required":["host","guest","readonly","tag"]},"Path":{"type":"string","description":"UTF-8 filesystem path."},"GuestMountPath":{"type":"string","minLength":2,"maxLength":4095,"pattern":"^/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+)(?:/(?:(?!\\.{1,2}(?:/|$))[^/\\u0000-\\u001F\\u007F]+))*$","description":"Canonical absolute non-root guest path with no dot components, duplicate separators, trailing slash, NUL, or ASCII control characters. Linux byte and component limits are validated after decoding."},"CloudInitSpec":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"],"description":"Inline user part, at most 32 KiB. Mutually exclusive with user_data."},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"type":"array","items":{"$ref":"#/components/schemas/Path"}},"ssh_authorized_keys":{"type":"array","items":{"type":"string"},"description":"Inline OpenSSH public keys, deduplicated together with ssh_keys."},"password":{"type":["string","null"],"description":"Plaintext guest password for user, 1 to 256 bytes without control characters."},"ssh_pwauth":{"type":"boolean"},"provisioning":{"type":"boolean"}},"additionalProperties":false,"required":["user_data","user_data_inline","network_config","ssh_keys","ssh_authorized_keys","password","ssh_pwauth","provisioning"]},"VmmSpec":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"$ref":"#/components/schemas/Firmware"},"extra_args":{"type":"array","items":{"type":"string"}},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"required":["binary","firmware","extra_args","config_overlay"]},"Firmware":{"type":"string","minLength":1,"description":"auto, rhf, edk2, or a non-empty UTF-8 firmware path."},"JsonObject":{"type":"object","additionalProperties":true,"description":"JSON object; nested null values retain RFC 7396 deletion semantics."},"SpecWarning":{"type":"object","properties":{"key":{"type":"string"},"message":{"type":"string"}},"additionalProperties":false,"required":["key","message"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"MachineSpecPatch":{"type":"object","properties":{"clear":{"type":"array","items":{"$ref":"#/components/schemas/SpecClear"},"uniqueItems":true},"image":{"anyOf":[{"$ref":"#/components/schemas/MachineImageRef"},{"type":"null"}]},"arch":{"anyOf":[{"$ref":"#/components/schemas/Architecture"},{"type":"null"}]},"cpus":{"type":["integer","null"],"minimum":1,"maximum":255},"cpus_max":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"Optional vCPU hotplug ceiling; must be at least cpus."},"memory":{"anyOf":[{"$ref":"#/components/schemas/MemorySizeInput"},{"type":"null"}]},"memory_max":{"anyOf":[{"$ref":"#/components/schemas/MemorySizeInput"},{"type":"null"}],"description":"Optional memory hotplug ceiling; must be at least memory."},"disk":{"anyOf":[{"$ref":"#/components/schemas/ByteSizeInput"},{"type":"null"}]},"user":{"type":["string","null"],"pattern":"^[a-z_][a-z0-9_-]*$"},"network":{"anyOf":[{"$ref":"#/components/schemas/NetworkSpecPatch"},{"type":"null"}]},"mount":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/MountSpecInput"},"maxItems":16},{"type":"null"}]},"cloud_init":{"anyOf":[{"$ref":"#/components/schemas/CloudInitSpecPatch"},{"type":"null"}]},"vmm":{"anyOf":[{"$ref":"#/components/schemas/VmmSpecPatch"},{"type":"null"}]}},"additionalProperties":false,"description":"Sparse layer used by create and PATCH. Every property is optional. Null Option-backed values are treated as absent, not as clear operations. clear is the only way to clear optional or vector leaves; a layer cannot set and clear the same leaf.","allOf":[{"not":{"properties":{"clear":{"contains":{"const":"arch"}},"arch":{"not":{"type":"null"}}},"required":["clear","arch"]}},{"not":{"properties":{"clear":{"contains":{"const":"network.forward"}},"network":{"type":"object","properties":{"forward":{"not":{"type":"null"}}},"required":["forward"]}},"required":["clear","network"]}},{"not":{"properties":{"clear":{"contains":{"const":"network.tap"}},"network":{"type":"object","properties":{"tap":{"not":{"type":"null"}}},"required":["tap"]}},"required":["clear","network"]}},{"not":{"properties":{"clear":{"contains":{"const":"network.mac"}},"network":{"type":"object","properties":{"mac":{"not":{"type":"null"}}},"required":["mac"]}},"required":["clear","network"]}},{"not":{"properties":{"clear":{"contains":{"const":"mount"}},"mount":{"not":{"type":"null"}}},"required":["clear","mount"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.user_data"}},"cloud_init":{"type":"object","properties":{"user_data":{"not":{"type":"null"}}},"required":["user_data"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.user_data_inline"}},"cloud_init":{"type":"object","properties":{"user_data_inline":{"not":{"type":"null"}}},"required":["user_data_inline"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.network_config"}},"cloud_init":{"type":"object","properties":{"network_config":{"not":{"type":"null"}}},"required":["network_config"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.ssh_keys"}},"cloud_init":{"type":"object","properties":{"ssh_keys":{"not":{"type":"null"}}},"required":["ssh_keys"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.password"}},"cloud_init":{"type":"object","properties":{"password":{"not":{"type":"null"}}},"required":["password"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"cloud_init.ssh_authorized_keys"}},"cloud_init":{"type":"object","properties":{"ssh_authorized_keys":{"not":{"type":"null"}}},"required":["ssh_authorized_keys"]}},"required":["clear","cloud_init"]}},{"not":{"properties":{"clear":{"contains":{"const":"vmm.binary"}},"vmm":{"type":"object","properties":{"binary":{"not":{"type":"null"}}},"required":["binary"]}},"required":["clear","vmm"]}},{"not":{"properties":{"clear":{"contains":{"const":"vmm.extra_args"}},"vmm":{"type":"object","properties":{"extra_args":{"not":{"type":"null"}}},"required":["extra_args"]}},"required":["clear","vmm"]}},{"not":{"properties":{"clear":{"contains":{"const":"vmm.config_overlay"}},"vmm":{"type":"object","properties":{"config_overlay":{"not":{"type":"null"}}},"required":["config_overlay"]}},"required":["clear","vmm"]}}]},"SpecClear":{"type":"string","enum":["arch","network.forward","network.tap","network.mac","mount","cloud_init.user_data","cloud_init.user_data_inline","cloud_init.network_config","cloud_init.ssh_keys","cloud_init.ssh_authorized_keys","cloud_init.password","vmm.binary","vmm.extra_args","vmm.config_overlay","cpus_max","memory_max"]},"MemorySizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)[Mm]?\\s*$","description":"Whole MiB from 128 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)[Gg]\\s*$","description":"Whole GiB from 1 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":128,"maximum":17592186044415,"description":"Whole MiB."}],"description":"Machine memory must resolve to at least 128 MiB and fit in u64 bytes."},"ByteSizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:0|(?:[1-9][0-9]{0,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415))[Mm]?\\s*$","description":"Whole MiB with no suffix or M/m, from 0 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:0|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183))[Gg]\\s*$","description":"Whole GiB with G/g, from 0 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":0,"maximum":17592186044415,"description":"Whole MiB."}]},"NetworkSpecPatch":{"type":"object","properties":{"mode":{"anyOf":[{"$ref":"#/components/schemas/NetMode"},{"type":"null"}]},"forward":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/PortForward"}},{"type":"null"}]},"tap":{"type":["string","null"],"description":"Empty text is accepted while inactive; the effective value is validated as a Linux TAP name when mode is tap."},"mac":{"anyOf":[{"$ref":"#/components/schemas/MacAddress"},{"type":"null"}]}},"additionalProperties":false,"description":"Sparse network layer. Missing or null properties make no change; use the root clear list to remove an effective value."},"MountSpecInput":{"type":"object","properties":{"host":{"$ref":"#/components/schemas/Path"},"guest":{"$ref":"#/components/schemas/GuestMountPath"},"readonly":{"type":"boolean","default":false},"tag":{"type":["string","null"],"minLength":1,"maxLength":36,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,35}$"}},"additionalProperties":false,"required":["host","guest"],"description":"One virtio-fs mount. host and guest are required; readonly defaults to false and tag defaults to a generated shareN value when omitted."},"CloudInitSpecPatch":{"type":"object","properties":{"user_data":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"user_data_inline":{"type":["string","null"]},"network_config":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"ssh_keys":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/Path"}},{"type":"null"}]},"ssh_authorized_keys":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"password":{"type":["string","null"]},"ssh_pwauth":{"type":["boolean","null"]},"provisioning":{"type":["boolean","null"]}},"additionalProperties":false,"description":"Sparse cloud-init layer. Missing or null properties make no change."},"VmmSpecPatch":{"type":"object","properties":{"binary":{"anyOf":[{"$ref":"#/components/schemas/Path"},{"type":"null"}]},"firmware":{"anyOf":[{"$ref":"#/components/schemas/Firmware"},{"type":"null"}]},"extra_args":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"config_overlay":{"anyOf":[{"$ref":"#/components/schemas/JsonObject"},{"type":"null"}]}},"additionalProperties":false,"description":"Sparse VMM layer. config_overlay must be an object when non-null."}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Start a machine

> Streams shared action Events by default. Accept: application/json waits for completion and aggregates progress. Closing a mutation response stops delivery but the action continues to a safe point.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/start":{"post":{"tags":["Machines"],"operationId":"startMachine","summary":"Start a machine","description":"Streams shared action Events by default. Accept: application/json waits for completion and aggregates progress. Closing a mutation response stops delivery but the action continues to a safe point.","responses":{"200":{"description":"Start progress and terminal running result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/StartDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}],"requestBody":{"required":false,"description":"Optional JSON object. A zero-byte body or {} uses wait=true and the configured start timeout; top-level JSON null is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartRequest"}}}}}}},"components":{"schemas":{"StartDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/StartResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"StartResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"start"},"payload":{"$ref":"#/components/schemas/StartResult"}},"additionalProperties":false,"required":["type","action","payload"]},"StartResult":{"type":"object","properties":{"name":{"type":"string"},"status":{"$ref":"#/components/schemas/MachineStatus"},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000},"forwards":{"type":"array","items":{"type":"string"}},"mounts":{"type":"array","items":{"type":"string"}}},"additionalProperties":false,"required":["name","status","elapsed_ms","forwards","mounts"]},"MachineStatus":{"type":"string","enum":["created","starting","running","stopping","stopped","failed"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"StartRequest":{"type":"object","properties":{"wait":{"type":["boolean","null"],"default":true,"description":"Wait for guest SSH readiness when true."},"timeout_s":{"type":["integer","null"],"minimum":1,"maximum":3600,"description":"Whole-second start/readiness deadline. Omission or null uses the configured start timeout."}},"additionalProperties":false,"description":"Optional JSON body. An empty HTTP body is equivalent to {}."}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Stop a machine

> Streams shared stop Events by default or aggregates when Accept selects application/json.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/stop":{"post":{"tags":["Machines"],"operationId":"stopMachine","summary":"Stop a machine","description":"Streams shared stop Events by default or aggregates when Accept selects application/json.","responses":{"200":{"description":"Stop progress and terminal stopped result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/StopDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}],"requestBody":{"required":false,"description":"Optional JSON object. A zero-byte body or {} uses force=false and the configured stop timeout; top-level JSON null is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopRequest"}}}}}}},"components":{"schemas":{"StopDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/StopResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"StopResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"stop"},"payload":{"$ref":"#/components/schemas/StopResult"}},"additionalProperties":false,"required":["type","action","payload"]},"StopResult":{"type":"object","properties":{"name":{"type":"string"},"status":{"$ref":"#/components/schemas/MachineStatus"},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["name","status","elapsed_ms"]},"MachineStatus":{"type":"string","enum":["created","starting","running","stopping","stopped","failed"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"StopRequest":{"type":"object","properties":{"timeout_s":{"type":["integer","null"],"minimum":1,"maximum":3600,"description":"Whole-second stop deadline. Omission or null uses the configured stop timeout."},"force":{"type":["boolean","null"],"default":false,"description":"Allow forced teardown after the graceful stop path."}},"additionalProperties":false,"description":"Optional JSON body. An empty HTTP body is equivalent to {}."}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Restart a machine

> The HTTP request body must contain zero bytes; even {} is rejected. Restart uses the configured start timeout and the configured stop timeout, with no route-local timeout field.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/restart":{"post":{"tags":["Machines"],"operationId":"restartMachine","summary":"Restart a machine","description":"The HTTP request body must contain zero bytes; even {} is rejected. Restart uses the configured start timeout and the configured stop timeout, with no route-local timeout field.","responses":{"200":{"description":"Restart progress and terminal running result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/RestartDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"RestartDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/RestartResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"RestartResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"restart"},"payload":{"$ref":"#/components/schemas/StartResult"}},"additionalProperties":false,"required":["type","action","payload"]},"StartResult":{"type":"object","properties":{"name":{"type":"string"},"status":{"$ref":"#/components/schemas/MachineStatus"},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000},"forwards":{"type":"array","items":{"type":"string"}},"mounts":{"type":"array","items":{"type":"string"}}},"additionalProperties":false,"required":["name","status","elapsed_ms","forwards","mounts"]},"MachineStatus":{"type":"string","enum":["created","starting","running","stopping","stopped","failed"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Read machine logs

> Returns sanitized text chunks from the selected owned log. Printable text, newline, carriage return and tab are preserved, and an SGR colour sequence (ESC \[ followed by at most 16 bytes of \[0-9;] then the final byte m) passes through verbatim. Every other escape sequence is swallowed whole and replaced with a single U+FFFD, including other CSI finals, OSC with either its BEL or ESC \ terminator, DCS, APC and an overlong CSI; every other Unicode control character, bare C1 included, is replaced with U+FFFD. The filter is stateful across chunks, so a sequence split between chunks parses once and a sequence still open when the stream ends is flushed as one U+FFFD. A Result before Output yields an empty 200. An error before Output is JSON; an error after streaming begins closes the text stream without an error record. Request bodies are ignored.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/logs":{"get":{"tags":["Machines"],"operationId":"getMachineLogs","summary":"Read machine logs","description":"Returns sanitized text chunks from the selected owned log. Printable text, newline, carriage return and tab are preserved, and an SGR colour sequence (ESC [ followed by at most 16 bytes of [0-9;] then the final byte m) passes through verbatim. Every other escape sequence is swallowed whole and replaced with a single U+FFFD, including other CSI finals, OSC with either its BEL or ESC \\ terminator, DCS, APC and an overlong CSI; every other Unicode control character, bare C1 included, is replaced with U+FFFD. The filter is stateful across chunks, so a sequence split between chunks parses once and a sequence still open when the stream ends is flushed as one U+FFFD. A Result before Output yields an empty 200. An error before Output is JSON; an error after streaming begins closes the text stream without an error record. Request bodies are ignored.","responses":{"200":{"description":"Sanitized log bytes with SGR colour preserved, streamed without an added delimiter.","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"},{"$ref":"#/components/parameters/LogSource"},{"$ref":"#/components/parameters/LogFollow"},{"$ref":"#/components/parameters/LogLines"}]}}},"components":{"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}},"LogSource":{"name":"source","in":"query","required":false,"description":"Owned log source. virtiofsd-N accepts a decimal u16 index from 0 through 65535. Defaults to console.","schema":{"type":"string","pattern":"^(?:console|vmm|shim|passt|virtiofsd-0*(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))$","default":"console"}},"LogFollow":{"name":"follow","in":"query","required":false,"description":"Keep the text stream open and follow safe rotations. Defaults to false.","schema":{"type":"boolean","default":false}},"LogLines":{"name":"lines","in":"query","required":false,"description":"Number of trailing lines. Zero is valid.","schema":{"type":"integer","minimum":0,"maximum":100000,"default":200}}}}}
```

## Get generated Cloud Hypervisor config

> Returns the canonical persisted Cloud Hypervisor v53 JSON value (maximum 51,200 bytes). Validated config\_overlay data may add fields, so the schema deliberately remains extensible. Request bodies and undocumented query fields are ignored.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/vmconfig":{"get":{"tags":["Machines"],"operationId":"getMachineVmConfig","summary":"Get generated Cloud Hypervisor config","description":"Returns the canonical persisted Cloud Hypervisor v53 JSON value (maximum 51,200 bytes). Validated config_overlay data may add fields, so the schema deliberately remains extensible. Request bodies and undocumented query fields are ignored.","responses":{"200":{"description":"Canonical VmConfig.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VmConfig"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"VmConfig":{"type":"object","properties":{"cpus":{"$ref":"#/components/schemas/VmCpusConfig"},"memory":{"$ref":"#/components/schemas/VmMemoryConfig"},"payload":{"$ref":"#/components/schemas/VmPayloadConfig"},"disks":{"type":"array","prefixItems":[{"$ref":"#/components/schemas/VmMachineDisk"},{"$ref":"#/components/schemas/VmSeedDisk"}],"items":{"$ref":"#/components/schemas/VmAdditionalDisk"},"minItems":2},"net":{"type":"array","prefixItems":[{"$ref":"#/components/schemas/VmNetConfig"}],"items":{},"minItems":1,"description":"The Firestone-owned first entry is typed; validated config_overlay may append Cloud Hypervisor entries."},"fs":{"type":"array","items":{},"contains":{"$ref":"#/components/schemas/VmFsConfig"},"minContains":1,"minItems":1,"description":"Contains the Firestone-owned filesystem entries; validated config_overlay may append Cloud Hypervisor entries."},"vsock":{"$ref":"#/components/schemas/VmVsockConfig"},"serial":{"$ref":"#/components/schemas/VmSerialConfig"},"console":{"$ref":"#/components/schemas/VmConsoleConfig"},"rng":{"$ref":"#/components/schemas/VmRngConfig"}},"additionalProperties":true,"required":["cpus","memory","payload","disks","vsock","serial","console","rng"],"description":"Canonical Cloud Hypervisor v53 VmConfig persisted for the machine. net and fs are omitted when disabled. A validated RFC 7396 config overlay may add fields but cannot change Firestone-owned required values."},"VmCpusConfig":{"type":"object","properties":{"boot_vcpus":{"type":"integer","minimum":1,"maximum":255},"max_vcpus":{"type":"integer","minimum":1,"maximum":255}},"additionalProperties":true,"required":["boot_vcpus","max_vcpus"],"description":"Firestone emits boot_vcpus from cpus and max_vcpus from cpus_max, defaulting to cpus."},"VmMemoryConfig":{"type":"object","properties":{"size":{"type":"integer","minimum":134217728,"maximum":18446744073709552000},"shared":{"type":"boolean","const":true},"hotplug_size":{"type":"integer","minimum":0,"maximum":18446744073709552000,"description":"Present only when memory_max is set; equals memory_max minus memory."}},"additionalProperties":true,"required":["size","shared"]},"VmPayloadConfig":{"type":"object","properties":{"firmware":{"$ref":"#/components/schemas/Path"},"kernel":{"$ref":"#/components/schemas/Path"}},"oneOf":[{"required":["firmware"]},{"required":["kernel"]}],"additionalProperties":true,"description":"Exactly one Firestone-owned boot payload is present. A validated config overlay may add non-conflicting Cloud Hypervisor fields."},"Path":{"type":"string","description":"UTF-8 filesystem path."},"VmMachineDisk":{"type":"object","properties":{"path":{"$ref":"#/components/schemas/Path"},"readonly":{"type":"boolean","const":false},"image_type":{"type":"string","const":"Qcow2"},"backing_files":{"type":"boolean","const":true},"vhost_user":{"type":"boolean","const":false}},"additionalProperties":true,"required":["path","image_type","backing_files"],"description":"First disk: writable qcow2 overlay. readonly is absent or false."},"VmSeedDisk":{"type":"object","properties":{"path":{"$ref":"#/components/schemas/Path"},"readonly":{"type":"boolean","const":true},"image_type":{"type":"string","const":"Raw"},"backing_files":{"type":"boolean","const":false},"vhost_user":{"type":"boolean","const":false}},"additionalProperties":true,"required":["path","readonly","image_type"],"description":"Second disk: read-only raw CIDATA seed. backing_files is absent or false."},"VmAdditionalDisk":{"description":"Additional Cloud Hypervisor disk supplied by a validated config overlay."},"VmNetConfig":{"type":"object","properties":{"tap":{"type":"string"},"mac":{"$ref":"#/components/schemas/MacAddress"},"ip":{"anyOf":[{"type":"string","format":"ipv4"},{"type":"string","format":"ipv6"}]},"mask":{"anyOf":[{"type":"string","format":"ipv4"},{"type":"string","format":"ipv6"}]},"vhost_user":{"type":"boolean"},"vhost_socket":{"type":"string"},"vhost_mode":{"type":"string","const":"Client"}},"additionalProperties":true,"required":["mac"],"description":"Tap fields or passt vhost-user fields are present according to the resolved network plan; absent optional fields are omitted."},"MacAddress":{"type":"string","pattern":"^[0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5}$"},"VmFsConfig":{"type":"object","properties":{"tag":{"type":"string","minLength":1,"maxLength":36},"socket":{"$ref":"#/components/schemas/Path"},"num_queues":{"type":"integer","const":1},"queue_size":{"type":"integer","const":1024}},"additionalProperties":true,"required":["tag","socket","num_queues","queue_size"]},"VmVsockConfig":{"type":"object","properties":{"cid":{"type":"integer","const":3},"socket":{"$ref":"#/components/schemas/Path"}},"additionalProperties":true,"required":["cid","socket"]},"VmSerialConfig":{"type":"object","properties":{"mode":{"type":"string","const":"File"},"file":{"$ref":"#/components/schemas/Path"}},"additionalProperties":true,"required":["mode","file"]},"VmConsoleConfig":{"type":"object","properties":{"mode":{"type":"string","const":"Pty"}},"additionalProperties":true,"required":["mode"]},"VmRngConfig":{"type":"object","properties":{"src":{"type":"string","const":"/dev/urandom"}},"additionalProperties":true,"required":["src"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Sample machine metrics once

> Returns one cumulative resource sample for a running machine, read from the VMM vm.counters and vm.info endpoints and the host /proc entries for the VMM process. Counters are cumulative since VMM start; clients derive rates from two samples. A machine that is not running returns 409. Request bodies and undocumented query fields are ignored.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/metrics":{"get":{"tags":["Machines"],"operationId":"getMachineMetrics","summary":"Sample machine metrics once","description":"Returns one cumulative resource sample for a running machine, read from the VMM vm.counters and vm.info endpoints and the host /proc entries for the VMM process. Counters are cumulative since VMM start; clients derive rates from two samples. A machine that is not running returns 409. Request bodies and undocumented query fields are ignored.","responses":{"200":{"description":"One metrics sample.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"MetricsResult":{"type":"object","description":"One cumulative resource sample for a running machine. Firestone runs no metrics daemon and stores no history, so clients derive rates from two samples.","properties":{"sampled_at":{"type":"string","format":"date-time","description":"RFC 3339 instant at which the host and VMM sources were read."},"cpu":{"$ref":"#/components/schemas/MetricsCpu"},"memory":{"$ref":"#/components/schemas/MetricsMemory"},"block":{"type":"array","items":{"$ref":"#/components/schemas/MetricsBlockDevice"}},"net":{"type":["array","null"],"description":"Network devices, or null when the VMM reports none. Cloud Hypervisor v53 reports no network counters under the default vhost-user passt path.","items":{"$ref":"#/components/schemas/MetricsNetDevice"}}},"additionalProperties":false,"required":["sampled_at","cpu","memory","block","net"]},"MetricsCpu":{"type":"object","properties":{"vcpus":{"type":"integer","description":"Guest vCPU count from the machine spec.","minimum":1,"maximum":255},"cpu_time_ns":{"type":["integer","null"],"description":"Cumulative VMM user plus system time in nanoseconds, or null when the host exposes no /proc sample.","minimum":0,"maximum":9223372036854776000}},"additionalProperties":false,"required":["vcpus","cpu_time_ns"]},"MetricsMemory":{"type":"object","properties":{"rss_bytes":{"type":["integer","null"],"description":"VMM resident set size in bytes, or null when the host exposes no /proc sample.","minimum":0,"maximum":9223372036854776000},"allocated_bytes":{"type":"integer","description":"Guest memory requested by the machine spec, in bytes.","minimum":0,"maximum":18446744073709552000},"guest_actual_bytes":{"type":["integer","null"],"description":"Cloud Hypervisor memory_actual_size in bytes, or null when the VMM reports none.","minimum":0,"maximum":9223372036854776000}},"additionalProperties":false,"required":["rss_bytes","allocated_bytes","guest_actual_bytes"]},"MetricsBlockDevice":{"type":"object","description":"Cumulative virtio-block counters for one guest disk. A counter the VMM omits, or reports as a saturating sentinel, is null.","properties":{"device":{"type":"string","description":"Cloud Hypervisor device id, such as _disk0."},"read_bytes":{"type":["integer","null"],"description":"Bytes read from the device since VMM start.","minimum":0,"maximum":9223372036854776000},"written_bytes":{"type":["integer","null"],"description":"Bytes written to the device since VMM start.","minimum":0,"maximum":9223372036854776000},"read_ops":{"type":["integer","null"],"description":"Completed reads since VMM start.","minimum":0,"maximum":9223372036854776000},"write_ops":{"type":["integer","null"],"description":"Completed writes since VMM start.","minimum":0,"maximum":9223372036854776000}},"additionalProperties":false,"required":["device","read_bytes","written_bytes","read_ops","write_ops"]},"MetricsNetDevice":{"type":"object","description":"Cumulative counters for one guest network device, keyed as the VMM names them because Firestone has not verified v53 network counter names.","properties":{"device":{"type":"string","description":"Cloud Hypervisor device id, such as _net0."},"counters":{"type":"object","description":"Counter name to cumulative value, with saturating sentinels removed.","additionalProperties":{"type":"integer","minimum":0,"maximum":9223372036854776000}}},"additionalProperties":false,"required":["device","counters"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Clone a machine

> Copies the source machine's firestone.toml verbatim and, by default, its qcow2 overlay onto a new machine in created state. The source must be stopped or created. State, host keys, seed artifacts and snapshots are never copied; the clone derives a fresh MAC and cloud-init instance id from its own name.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/clone":{"post":{"tags":["Machines"],"operationId":"cloneMachine","summary":"Clone a machine","description":"Copies the source machine's firestone.toml verbatim and, by default, its qcow2 overlay onto a new machine in created state. The source must be stopped or created. State, host keys, seed artifacts and snapshots are never copied; the clone derives a fresh MAC and cloud-init instance id from its own name.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CloneMachineRequest"}}}},"responses":{"200":{"description":"Clone progress and the terminal clone result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/CloneDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"CloneMachineRequest":{"type":"object","properties":{"name":{"type":"string","description":"Destination machine name. One non-empty path component with no separators or control characters."},"fresh_disk":{"type":["boolean","null"],"default":false,"description":"Give the clone an empty overlay on the same base image instead of copying the source overlay."}},"additionalProperties":false,"required":["name"],"description":"Required JSON body. The source machine is the path name."},"CloneDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/CloneResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"CloneResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"clone"},"payload":{"$ref":"#/components/schemas/CloneResult"}},"additionalProperties":false,"required":["type","action","payload"]},"CloneResult":{"type":"object","properties":{"source":{"type":"string"},"dest":{"type":"string"},"disk_bytes":{"type":"integer","minimum":0,"maximum":18446744073709552000,"description":"Virtual size of the destination overlay, or zero when the source had no overlay to copy and none was created."}},"additionalProperties":false,"required":["source","dest","disk_bytes"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Resize a machine's CPU and memory

> Streams shared resize Events by default or aggregates when Accept selects application/json. A running machine is resized live only inside the max\_vcpus and hotplug\_size headroom of the VmConfig it booted with; a request beyond that headroom answers 409. A stopped machine is equivalent to a spec patch. The effective values are always persisted to the machine spec.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/resize":{"post":{"tags":["Machines"],"operationId":"resizeMachine","summary":"Resize a machine's CPU and memory","description":"Streams shared resize Events by default or aggregates when Accept selects application/json. A running machine is resized live only inside the max_vcpus and hotplug_size headroom of the VmConfig it booted with; a request beyond that headroom answers 409. A stopped machine is equivalent to a spec patch. The effective values are always persisted to the machine spec.","responses":{"200":{"description":"Resize progress and the terminal effective CPU and memory.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/ResizeDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}],"requestBody":{"required":true,"description":"Required JSON object naming the new cpus, memory, or both.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResizeRequest"}}}}}}},"components":{"schemas":{"ResizeDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/ResizeResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"ResizeResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"resize"},"payload":{"$ref":"#/components/schemas/ResizeResult"}},"additionalProperties":false,"required":["type","action","payload"]},"ResizeResult":{"type":"object","properties":{"name":{"type":"string"},"applied_live":{"type":"boolean","description":"True when Cloud Hypervisor accepted vm.resize for the running machine. False means the values were written to the spec and apply on the next start."},"cpus":{"type":"integer","minimum":1,"maximum":255},"memory":{"$ref":"#/components/schemas/MemorySize"}},"additionalProperties":false,"required":["name","applied_live","cpus","memory"]},"MemorySize":{"type":"string","pattern":"^(?:(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)M|(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)G)$","description":"Canonical effective memory size, at least 128 MiB."},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ResizeRequest":{"type":"object","properties":{"cpus":{"type":["integer","null"],"minimum":1,"maximum":255,"description":"New vCPU count. Omission or null leaves cpus unchanged."},"memory":{"anyOf":[{"$ref":"#/components/schemas/MemorySizeInput"},{"type":"null"}],"description":"New guest memory. Omission or null leaves memory unchanged."}},"additionalProperties":false,"description":"At least one of cpus and memory must resolve to a value; a body that changes nothing is a usage error."},"MemorySizeInput":{"oneOf":[{"type":"string","pattern":"^\\s*0*(?:12[8-9]|1[3-9][0-9]|[2-9][0-9]{2}|[1-9][0-9]{3,12}|1[0-6][0-9]{12}|17[0-4][0-9]{11}|175[0-8][0-9]{10}|1759[0-1][0-9]{9}|175920[0-9]{8}|175921[0-7][0-9]{7}|1759218[0-5][0-9]{6}|175921860[0-3][0-9]{4}|1759218604[0-3][0-9]{3}|17592186044[0-3][0-9]{2}|1759218604440[0-9]|1759218604441[0-4]|17592186044415)[Mm]?\\s*$","description":"Whole MiB from 128 through 17592186044415; surrounding whitespace and leading zeroes are accepted."},{"type":"string","pattern":"^\\s*0*(?:[1-9][0-9]{0,9}|1[0-6][0-9]{9}|170[0-9]{8}|171[0-6][0-9]{7}|1717[0-8][0-9]{6}|17179[0-7][0-9]{5}|171798[0-5][0-9]{4}|1717986[0-8][0-9]{3}|171798690[0-9]{2}|171798691[0-7][0-9]|1717986918[0-2]|17179869183)[Gg]\\s*$","description":"Whole GiB from 1 through 17179869183; surrounding whitespace and leading zeroes are accepted."},{"type":"integer","minimum":128,"maximum":17592186044415,"description":"Whole MiB."}],"description":"Machine memory must resolve to at least 128 MiB and fit in u64 bytes."}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Attach the machine console over a WebSocket

> Upgrades to a WebSocket carrying the machine's serial console. The single-client console broker is contacted and its acknowledgement read \*\*before\*\* the upgrade, so a console that is already attached is refused with a normal \`409\` naming \`firestone console \<name>\`, and no WebSocket is created. A machine that is not running is refused with the standard not-running error.\
> \
> Framing: binary frames are raw terminal bytes in both directions; text frames are JSON control messages. \`{"resize":{"rows":R,"cols":C}}\` is accepted and ignored on this route, because the guest owns its serial geometry. Any other text frame is ignored. The server closes with a descriptive close frame: code 1000 and reason \`machine stopped\` on end of file, or code 1011 and the failure detail on a transport error.\
> \
> This is a WebSocket handshake, not a JSON route: a successful request answers \`101 Switching Protocols\` with \`Upgrade: websocket\`. The handshake headers (\`Connection\`, \`Upgrade\`, \`Sec-WebSocket-Key\`, \`Sec-WebSocket-Version\`) are the standard RFC 6455 ones and are not repeated here. Firestone negotiates no subprotocol and no extension.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/console/ws":{"get":{"tags":["Machines"],"operationId":"openMachineConsoleWebSocket","summary":"Attach the machine console over a WebSocket","description":"Upgrades to a WebSocket carrying the machine's serial console. The single-client console broker is contacted and its acknowledgement read **before** the upgrade, so a console that is already attached is refused with a normal `409` naming `firestone console <name>`, and no WebSocket is created. A machine that is not running is refused with the standard not-running error.\n\nFraming: binary frames are raw terminal bytes in both directions; text frames are JSON control messages. `{\"resize\":{\"rows\":R,\"cols\":C}}` is accepted and ignored on this route, because the guest owns its serial geometry. Any other text frame is ignored. The server closes with a descriptive close frame: code 1000 and reason `machine stopped` on end of file, or code 1011 and the failure detail on a transport error.\n\nThis is a WebSocket handshake, not a JSON route: a successful request answers `101 Switching Protocols` with `Upgrade: websocket`. The handshake headers (`Connection`, `Upgrade`, `Sec-WebSocket-Key`, `Sec-WebSocket-Version`) are the standard RFC 6455 ones and are not repeated here. Firestone negotiates no subprotocol and no extension.","responses":{"101":{"description":"Upgraded. The connection now carries WebSocket frames."},"400":{"$ref":"#/components/responses/Error400"},"403":{"description":"The loopback session gate refused the upgrade. A protocol upgrade must additionally prove same-origin: `Sec-Fetch-Site: same-origin` or `none`, or an `Origin` in the bound loopback allowlist. A Unix listener has no gate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Open an SSH shell over a WebSocket

> Upgrades to a WebSocket carrying one interactive shell. The machine must be \`running\` before the upgrade. After the upgrade the server allocates a host pseudo-terminal and runs the same OpenSSH argv \`firestone shell\` execs, with the pseudo-terminal slave as the child's stdin, stdout and stderr; the master is relayed to the WebSocket. One session per connection: closing the WebSocket kills the child's process group and reaps it.\
> \
> Framing: binary frames are raw terminal bytes in both directions; text frames are JSON control messages. \`{"resize":{"rows":R,"cols":C}}\` applies \`TIOCSWINSZ\` to the pseudo-terminal master. Any other text frame is ignored. The server closes with a descriptive close frame: code 1000 and reason \`session ended\` when the shell ends, or code 1011 and the failure detail when the session could not be established.\
> \
> This is a WebSocket handshake, not a JSON route: a successful request answers \`101 Switching Protocols\` with \`Upgrade: websocket\`. The handshake headers (\`Connection\`, \`Upgrade\`, \`Sec-WebSocket-Key\`, \`Sec-WebSocket-Version\`) are the standard RFC 6455 ones and are not repeated here. Firestone negotiates no subprotocol and no extension.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/shell/ws":{"get":{"tags":["Machines"],"operationId":"openMachineShellWebSocket","summary":"Open an SSH shell over a WebSocket","description":"Upgrades to a WebSocket carrying one interactive shell. The machine must be `running` before the upgrade. After the upgrade the server allocates a host pseudo-terminal and runs the same OpenSSH argv `firestone shell` execs, with the pseudo-terminal slave as the child's stdin, stdout and stderr; the master is relayed to the WebSocket. One session per connection: closing the WebSocket kills the child's process group and reaps it.\n\nFraming: binary frames are raw terminal bytes in both directions; text frames are JSON control messages. `{\"resize\":{\"rows\":R,\"cols\":C}}` applies `TIOCSWINSZ` to the pseudo-terminal master. Any other text frame is ignored. The server closes with a descriptive close frame: code 1000 and reason `session ended` when the shell ends, or code 1011 and the failure detail when the session could not be established.\n\nThis is a WebSocket handshake, not a JSON route: a successful request answers `101 Switching Protocols` with `Upgrade: websocket`. The handshake headers (`Connection`, `Upgrade`, `Sec-WebSocket-Key`, `Sec-WebSocket-Version`) are the standard RFC 6455 ones and are not repeated here. Firestone negotiates no subprotocol and no extension.","responses":{"101":{"description":"Upgraded. The connection now carries WebSocket frames."},"400":{"$ref":"#/components/responses/Error400"},"403":{"description":"The loopback session gate refused the upgrade. A protocol upgrade must additionally prove same-origin: `Sec-Fetch-Site: same-origin` or `none`, or an `Origin` in the bound loopback allowlist. A Unix listener has no gate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## List machine snapshots

> Returns every published snapshot of one machine, ordered by identifier, projected from each snapshot's metadata.json. A snapshot still being written is invisible here. Request bodies and undocumented query fields are ignored.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/snapshots":{"get":{"tags":["Machines"],"operationId":"listMachineSnapshots","summary":"List machine snapshots","description":"Returns every published snapshot of one machine, ordered by identifier, projected from each snapshot's metadata.json. A snapshot still being written is invisible here. Request bodies and undocumented query fields are ignored.","responses":{"200":{"description":"Published snapshots of the machine.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotListResult"}}}},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"SnapshotListResult":{"type":"object","properties":{"snapshots":{"type":"array","items":{"$ref":"#/components/schemas/SnapshotSummary"},"description":"Published snapshots ordered by identifier. Partially written snapshots are never listed."}},"additionalProperties":false,"required":["snapshots"]},"SnapshotSummary":{"type":"object","properties":{"snapshot":{"type":"string"},"kind":{"$ref":"#/components/schemas/SnapshotKind"},"created_at":{"type":"string","description":"RFC 3339 UTC instant the snapshot was published."},"image_id":{"type":["string","null"],"description":"Stored image the snapshot overlay backs onto. Null when the machine had no pinned image. A non-null value pins the image against images rm and images prune."},"disk_bytes":{"type":"integer","minimum":0,"maximum":18446744073709552000},"memory_bytes":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["snapshot","kind","created_at","image_id","disk_bytes"]},"SnapshotKind":{"type":"string","enum":["cold","warm"],"description":"cold snapshots copy the spec and overlay of a stopped or created machine. warm snapshots also capture guest memory by pausing a running machine, writing its Cloud Hypervisor VM state, and resuming it."},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Capture a machine snapshot

> Captures one immutable snapshot. A stopped or created machine yields a cold snapshot: the spec, the published VmConfig when one exists, and a qcow2 overlay copy on the same base image. A running machine yields a warm snapshot, which also pauses the machine, writes its Cloud Hypervisor VM state, copies the overlay while paused, and resumes it. A machine that is starting, stopping, or failed returns 409, as does a snapshot name that is already taken.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/snapshots":{"post":{"tags":["Machines"],"operationId":"createMachineSnapshot","summary":"Capture a machine snapshot","description":"Captures one immutable snapshot. A stopped or created machine yields a cold snapshot: the spec, the published VmConfig when one exists, and a qcow2 overlay copy on the same base image. A running machine yields a warm snapshot, which also pauses the machine, writes its Cloud Hypervisor VM state, copies the overlay while paused, and resumes it. A machine that is starting, stopping, or failed returns 409, as does a snapshot name that is already taken.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSnapshotRequest"}}}},"responses":{"200":{"description":"Snapshot progress and the terminal snapshot result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotResultDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"}]}}},"components":{"schemas":{"CreateSnapshotRequest":{"type":"object","properties":{"snapshot":{"type":["string","null"],"minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_][A-Za-z0-9._-]*$","description":"Snapshot identifier. Absent or null asks Firestone for snap-<yyyymmdd>-<hhmmss> in UTC."}},"additionalProperties":false,"description":"Optional JSON body. An absent body is the same as {}."},"SnapshotResultDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/SnapshotResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"SnapshotResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"snapshot-create"},"payload":{"$ref":"#/components/schemas/SnapshotResult"}},"additionalProperties":false,"required":["type","action","payload"]},"SnapshotResult":{"type":"object","properties":{"name":{"type":"string"},"snapshot":{"type":"string"},"kind":{"$ref":"#/components/schemas/SnapshotKind"},"disk_bytes":{"type":"integer","minimum":0,"maximum":18446744073709552000,"description":"Virtual size of the copied overlay, or zero when the machine had none yet."},"memory_bytes":{"type":"integer","minimum":0,"maximum":18446744073709552000,"description":"Guest memory captured by a warm snapshot. Omitted entirely for a cold snapshot."}},"additionalProperties":false,"required":["name","snapshot","kind","disk_bytes"]},"SnapshotKind":{"type":"string","enum":["cold","warm"],"description":"cold snapshots copy the spec and overlay of a stopped or created machine. warm snapshots also capture guest memory by pausing a running machine, writing its Cloud Hypervisor VM state, and resuming it."},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}}}}}
```

## Restore a machine from a snapshot

> Whole-machine rollback: the snapshot's overlay, firestone.toml and vmconfig.json replace the machine's own. A running machine returns 409 unless force is true, which stops it first. A cold restore leaves the machine stopped unless start is true. A warm restore writes the machine's restore marker and always starts the machine, so the next launch resumes the captured guest memory instead of booting.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/snapshots/{snapshot}/restore":{"post":{"tags":["Machines"],"operationId":"restoreMachineSnapshot","summary":"Restore a machine from a snapshot","description":"Whole-machine rollback: the snapshot's overlay, firestone.toml and vmconfig.json replace the machine's own. A running machine returns 409 unless force is true, which stops it first. A cold restore leaves the machine stopped unless start is true. A warm restore writes the machine's restore marker and always starts the machine, so the next launch resumes the captured guest memory instead of booting.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreSnapshotRequest"}}}},"responses":{"200":{"description":"Restore progress and the terminal restore result.","content":{"application/x-ndjson":{"schema":{"type":"string","description":"LF-delimited compact JSON records. Progress records arrive as produced. Success ends with exactly one typed Result record; a dispatcher failure after progress ends with one ErrorEnvelope record under HTTP 200."}},"application/json":{"schema":{"$ref":"#/components/schemas/SnapshotRestoreResultDispatchOutput"}}}},"400":{"$ref":"#/components/responses/ActionError400"},"404":{"$ref":"#/components/responses/ActionError404"},"409":{"$ref":"#/components/responses/ActionError409"},"500":{"$ref":"#/components/responses/ActionError500"},"502":{"$ref":"#/components/responses/ActionError502"},"503":{"$ref":"#/components/responses/ActionError503"},"504":{"$ref":"#/components/responses/ActionError504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"},{"$ref":"#/components/parameters/SnapshotName"}]}}},"components":{"schemas":{"RestoreSnapshotRequest":{"type":"object","properties":{"force":{"type":["boolean","null"],"default":false,"description":"Stop a running machine before restoring instead of refusing with 409."},"start":{"type":["boolean","null"],"default":false,"description":"Start the machine after restoring a cold snapshot. A warm snapshot always starts the machine, because its restore is a resume."},"timeout_s":{"type":["integer","null"],"minimum":0,"maximum":3600,"description":"Deadline for the stop that force performs. Defaults to the configured stop timeout."}},"additionalProperties":false,"description":"Optional JSON body. An absent body is the same as {}."},"SnapshotRestoreResultDispatchOutput":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/NonTerminalEvent"}},"result":{"$ref":"#/components/schemas/SnapshotRestoreResultEvent"}},"additionalProperties":false,"required":["events","result"]},"NonTerminalEvent":{"oneOf":[{"$ref":"#/components/schemas/StepStartEvent"},{"$ref":"#/components/schemas/StepUpdateEvent"},{"$ref":"#/components/schemas/ProgressEvent"},{"$ref":"#/components/schemas/StepDoneEvent"},{"$ref":"#/components/schemas/StepSkipEvent"},{"$ref":"#/components/schemas/StepFailEvent"},{"$ref":"#/components/schemas/LogEvent"},{"$ref":"#/components/schemas/OutputEvent"}],"discriminator":{"propertyName":"type","mapping":{"StepStart":"#/components/schemas/StepStartEvent","StepUpdate":"#/components/schemas/StepUpdateEvent","Progress":"#/components/schemas/ProgressEvent","StepDone":"#/components/schemas/StepDoneEvent","StepSkip":"#/components/schemas/StepSkipEvent","StepFail":"#/components/schemas/StepFailEvent","Log":"#/components/schemas/LogEvent","Output":"#/components/schemas/OutputEvent"}}},"StepStartEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepStart"},"id":{"type":"string"},"label":{"type":"string"}},"additionalProperties":false,"required":["type","id","label"]},"StepUpdateEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepUpdate"},"id":{"type":"string"},"detail":{"type":"string"}},"additionalProperties":false,"required":["type","id","detail"]},"ProgressEvent":{"type":"object","properties":{"type":{"type":"string","const":"Progress"},"id":{"type":"string"},"done":{"type":"integer","minimum":0,"maximum":18446744073709552000},"total":{"anyOf":[{"type":"integer","minimum":0,"maximum":18446744073709552000},{"type":"null"}]},"unit":{"$ref":"#/components/schemas/Unit"}},"additionalProperties":false,"required":["type","id","done","total","unit"]},"Unit":{"type":"string","enum":["bytes"]},"StepDoneEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepDone"},"id":{"type":"string"},"detail":{"anyOf":[{"type":"string"},{"type":"null"}]},"elapsed_ms":{"type":"integer","minimum":0,"maximum":18446744073709552000}},"additionalProperties":false,"required":["type","id","detail","elapsed_ms"]},"StepSkipEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepSkip"},"id":{"type":"string"},"reason":{"type":"string"}},"additionalProperties":false,"required":["type","id","reason"]},"StepFailEvent":{"type":"object","properties":{"type":{"type":"string","const":"StepFail"},"id":{"type":"string"},"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["type","id","error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]},"LogEvent":{"type":"object","properties":{"type":{"type":"string","const":"Log"},"level":{"$ref":"#/components/schemas/Level"},"message":{"type":"string"}},"additionalProperties":false,"required":["type","level","message"]},"Level":{"type":"string","enum":["trace","debug","info","warn","error"]},"OutputEvent":{"type":"object","properties":{"type":{"type":"string","const":"Output"},"data":{"type":"string"}},"additionalProperties":false,"required":["type","data"]},"SnapshotRestoreResultEvent":{"type":"object","properties":{"type":{"type":"string","const":"Result"},"action":{"type":"string","const":"snapshot-restore"},"payload":{"$ref":"#/components/schemas/SnapshotRestoreResult"}},"additionalProperties":false,"required":["type","action","payload"]},"SnapshotRestoreResult":{"type":"object","properties":{"name":{"type":"string"},"snapshot":{"type":"string"},"started":{"type":"boolean","description":"True when the machine is running again after the restore."}},"additionalProperties":false,"required":["name","snapshot","started"]},"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]}},"responses":{"ActionError400":{"description":"Bad request: usage or invalid_spec. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError404":{"description":"Resource or route not found: not_found. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError409":{"description":"Conflict: conflict, already_running, or busy. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError502":{"description":"Image checksum or verification failure: checksum. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError503":{"description":"Host dependency unavailable or broken: dependency. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}},"ActionError504":{"description":"Bounded action deadline exceeded: timeout. Before the first event, a default-stream dispatcher error is one NDJSON line; request-validation errors remain JSON. With JSON aggregation selected, dispatcher errors are JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}},"application/x-ndjson":{"schema":{"type":"string","description":"One LF-terminated ErrorEnvelope record."}}}}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}},"SnapshotName":{"name":"snapshot","in":"path","required":true,"description":"Percent-decoded snapshot identifier: 1 to 64 characters from A-Z a-z 0-9 . _ - that do not start with '.' or '-'.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_][A-Za-z0-9._-]*$"}}}}}
```

## Delete one machine snapshot

> The request body and Accept header are ignored. Progress and the internal SnapshotRemoveResult are discarded; success is always empty 204. A snapshot named by a pending warm restore returns 409.

```json
{"openapi":"3.1.0","info":{"title":"Firestone REST API","version":"0.1.0"},"tags":[{"name":"Machines","description":"Machine desired state, lifecycle, logs, and generated VMM config."}],"servers":[{"url":"http://firestone","description":"Placeholder HTTP authority used by Unix-socket clients such as curl --unix-socket. No TCP connection is made."},{"url":"http://127.0.0.1:{port}","description":"Loopback TCP listener published by `firestone serve --listen tcp:127.0.0.1:PORT --token FILE` and by `firestone ui`. The bind address must be loopback and the listener must carry a token; both are refused before the socket is created otherwise.","variables":{"port":{"default":"8642","description":"Port passed to --listen, or the ephemeral port firestone ui binds"}}}],"paths":{"/v1/machines/{name}/snapshots/{snapshot}":{"delete":{"tags":["Machines"],"operationId":"deleteMachineSnapshot","summary":"Delete one machine snapshot","description":"The request body and Accept header are ignored. Progress and the internal SnapshotRemoveResult are discarded; success is always empty 204. A snapshot named by a pending warm restore returns 409.","responses":{"204":{"description":"Snapshot removed. Empty body and no Content-Type header."},"400":{"$ref":"#/components/responses/Error400"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"},"504":{"$ref":"#/components/responses/Error504"}},"parameters":[{"$ref":"#/components/parameters/MachineName"},{"$ref":"#/components/parameters/SnapshotName"}]}}},"components":{"responses":{"Error400":{"description":"Bad request: usage or invalid_spec.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error404":{"description":"Resource or route not found: not_found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error409":{"description":"Conflict: conflict, already_running, or busy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error500":{"description":"Internal action failure: generic, not_running, already_exists, or interrupted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error502":{"description":"Image checksum or verification failure: checksum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error503":{"description":"Host dependency unavailable or broken: dependency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Error504":{"description":"Bounded action deadline exceeded: timeout.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"ErrorEnvelope":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ErrorInfo"}},"additionalProperties":false,"required":["error"]},"ErrorInfo":{"type":"object","properties":{"kind":{"$ref":"#/components/schemas/ErrorKind"},"message":{"type":"string"},"hint":{"type":"string"},"field":{"type":"string"}},"additionalProperties":false,"required":["kind","message"],"description":"hint is omitted when the error has no public remediation hint. field is omitted unless the error belongs to one machine-spec leaf; when present it is that leaf's dotted path, such as memory, network.forward, mount[0].host or cloud_init.password."},"ErrorKind":{"type":"string","enum":["generic","usage","invalid_spec","not_found","not_running","conflict","already_exists","already_running","busy","dependency","timeout","checksum","interrupted"]}},"parameters":{"MachineName":{"name":"name","in":"path","required":true,"description":"Percent-decoded UTF-8 machine name. Core path validation requires one non-empty Unix path component without control characters.","schema":{"type":"string","minLength":1,"pattern":"^(?!\\.{1,2}$)[^/\\u0000-\\u001F\\u007F-\\u009F]+$"}},"SnapshotName":{"name":"snapshot","in":"path","required":true,"description":"Percent-decoded snapshot identifier: 1 to 64 characters from A-Z a-z 0-9 . _ - that do not start with '.' or '-'.","schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_][A-Za-z0-9._-]*$"}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://firestonevm.gitbook.io/docs/api-reference/machines.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
