@@ -176,6 +176,30 @@ Add a host with a custom GitHub user to override the SSH keys:
176176}
177177` ` `
178178
179+ # ## Block until ready (`?wait=` and `?timeout=`)
180+
181+ By default, `POST /hostgroup/NAME/nodes` returns as soon as the VM is
182+ scheduled — the in-guest agent may still be booting. Two optional query
183+ parameters let the server hold the response until readiness, so callers
184+ don't need their own poll loop on `/vm/{hostname}/health` :
185+
186+ - ` wait=agent` — block until `agent_uptime > 0` (the agent is up and can
187+ accept `exec` calls).
188+ - ` wait=userdata` — additionally block until `userdata_ran == true`
189+ (the cloud-init-style userdata script has completed).
190+ - ` timeout=30s` — Go-style duration. Defaults to `5m` when `wait` is
191+ set. On timeout the VM is cleaned up and the endpoint returns **408**.
192+
193+ ` ` ` bash
194+ curl --unix-socket ~/slicer-mac/slicer.sock \
195+ -X POST "http://localhost/hostgroup/sbox/nodes?wait=agent&timeout=30s" \
196+ -H "Content-Type: application/json" \
197+ -d '{"cpus":1,"ram_bytes":1073741824}'
198+ ` ` `
199+
200+ Typical response latency on Slicer-for-Mac is ~450 ms for `wait=agent`
201+ on a 1 vCPU / 1 GiB sandbox.
202+
179203# # List nodes in a Host Group
180204
181205HTTP GET
@@ -366,11 +390,18 @@ Query parameters:
366390- `stdout` (optional) : enable stdout capture (true/false)
367391- `stderr` (optional) : enable stderr capture (true/false)
368392- `permissions` (optional) : permissions for the command
393+ - `buffered` (optional) : see **Buffered exec** below.
369394
370395Body : stdin data (if `stdin=true`)
371396
372397Response : streaming newline-delimited JSON with stdout/stderr/exit_code
373398
399+ Newer agents emit typed frames on the streaming response — `started`
400+ (first frame, carries `pid` and `started_at`), `stdout`, `stderr`, and
401+ ` exit` (last frame, carries `exit_code` and `ended_at`). Older agents
402+ emit untyped frames that mix `stdout`/`stderr`/`exit_code` on a single
403+ object; clients should tolerate both shapes.
404+
374405Example response stream :
375406
376407` ` ` json
@@ -389,6 +420,87 @@ The `error` variable may also be populated if there was a problem running, start
389420{"error": "Some error message", "exit_code": 1}
390421` ` `
391422
423+ # ## Buffered exec (`?buffered=true`)
424+
425+ For callers that don't need live output, add `buffered=true` to get a
426+ single JSON response instead of an NDJSON stream :
427+
428+ ` ` ` bash
429+ curl --unix-socket ~/slicer-mac/slicer.sock \
430+ -X POST "http://localhost/vm/sbox-1/exec?buffered=true&cmd=/bin/bash&args=-lc&args=echo%20hello" \
431+ -H "Content-Type: application/json"
432+ ` ` `
433+
434+ Response :
435+
436+ ` ` ` json
437+ { "stdout": "hello\n ", "stderr": "", "exit_code": 0 }
438+ ` ` `
439+
440+ The request shape is the same (query parameters, not a JSON body). The
441+ response does not include `started_at` / `ended_at` — those are only on
442+ streaming frames. `stdin` is not supported with `buffered=true`; use
443+ the streaming endpoint if you need to pipe stdin.
444+
445+ # # Filesystem operations
446+
447+ HTTP endpoints under `/vm/{hostname}/fs/*` read and mutate the guest
448+ filesystem directly via the in-guest agent. Prefer these over shelling
449+ out through `/exec` — they're faster, don't depend on `ls`/`stat`/`mkdir`
450+ being on the guest PATH, and avoid shell-quoting hazards on unusual
451+ filenames.
452+
453+ # ## List a directory
454+
455+ HTTP GET
456+
457+ ` /vm/{hostname}/fs/readdir?path=/etc`
458+
459+ Response :
460+
461+ ` ` ` json
462+ [
463+ {"name":"hostname","type":"file","size":7,"mtime":1776024825,"mode":"0644"},
464+ {"name":"ssh","type":"directory","size":4096,"mtime":1776024825,"mode":"0755"},
465+ {"name":"localtime","type":"symlink","size":27,"mtime":1775348015,"mode":"0777"}
466+ ]
467+ ` ` `
468+
469+ ` type` is one of `file`, `directory`, or `symlink`. `mtime` is a Unix
470+ timestamp in seconds; `mode` is the octal file mode.
471+
472+ # ## Stat a single entry
473+
474+ HTTP GET
475+
476+ ` /vm/{hostname}/fs/stat?path=/etc/hostname`
477+
478+ Response : a single `SlicerFSInfo` object (same shape as one entry from
479+ ` readdir` ). Returns **404** if the path does not exist — useful as a
480+ cheap `exists` check.
481+
482+ # ## Create a directory
483+
484+ HTTP POST
485+
486+ ` /vm/{hostname}/fs/mkdir`
487+
488+ Body :
489+
490+ ` ` ` json
491+ { "path": "/tmp/work", "recursive": true, "mode": "0755" }
492+ ` ` `
493+
494+ ` recursive` and `mode` are optional.
495+
496+ # ## Remove a file or directory
497+
498+ HTTP DELETE
499+
500+ ` /vm/{hostname}/fs/remove?path=/tmp/work&recursive=true`
501+
502+ Returns 200 on success.
503+
392504# # Manage secrets
393505
394506HTTP GET
@@ -497,6 +609,50 @@ HTTP POST
497609
498610Response 200 : text/plain
499611
612+ # # Suspend a VM to disk (Slicer-for-Mac only, for now)
613+
614+ HTTP POST
615+
616+ ` /vm/{hostname}/suspend`
617+
618+ Takes a Firecracker snapshot of the VM's memory and disk state, then
619+ shuts down the underlying VM process. Memory is released. Use
620+ ` /restore` to bring the VM back up from the snapshot.
621+
622+ > Availability: currently supported on Slicer-for-Mac only. Not
623+ > available on the Linux daemon yet.
624+
625+ Response 200 : text/plain
626+
627+ # # Restore a VM from a snapshot (Slicer-for-Mac only, for now)
628+
629+ HTTP POST
630+
631+ ` /vm/{hostname}/restore`
632+
633+ Restores a previously-suspended VM from its Firecracker snapshot. The
634+ VM resumes with its memory and disk state intact.
635+
636+ > Availability: currently supported on Slicer-for-Mac only. Not
637+ > available on the Linux daemon yet.
638+
639+ Response 200 : text/plain
640+
641+ # # Relaunch an API-launched VM
642+
643+ HTTP POST
644+
645+ ` /vm/{hostname}/relaunch`
646+
647+ Bring a previously-created API-launched VM back up using its existing
648+ disk image, without going through a fresh `POST /hostgroup/NAME/nodes`.
649+ Useful after an intentional shutdown when you want to resume the same
650+ sandbox identity rather than spin up a new one.
651+
652+ Available on both Slicer-for-Mac and the Linux daemon.
653+
654+ Response 200 : ` SlicerCreateNodeResponse`
655+
500656# # Forward TCP connections
501657
502658HTTP GET
0 commit comments