@finalclass SessionOne running MicroVM’s control API, with the proxy auth handled for you.
Constructor
Section titled “Constructor”Session declares no __new__ or __init__, so it is not constructed directly: an instance comes back from another call in this package.
Properties
Section titled “Properties”agent_token
Section titled “agent_token”agent_token: strThe guest bearer credential. Store only in a private encrypted control record. It is never included in repr or ordinary status output.
egress_posture
Section titled “egress_posture”egress_posture: strThe launch’s egress posture: "open", "unsealed", "best-effort", or "sealed".
The value the CLI envelope’s egressPosture reports for the same launch options, and
what egress_posture_for answers before the launch. A session that does not hold its
launch options (Session.direct, Session.attach, an adopted sandbox) reports
"unsealed". Advertise network isolation only for "sealed".
endpoint
Section titled “endpoint”endpoint: strThe endpoint this session addresses.
A String rather than a &str because a sandbox-held session reads it under the
lock, and a reference would outlive the guard.
launch_metrics
Section titled “launch_metrics”launch_metrics: dict | NoneLaunch observations, or None for a session not created by a launch.
port: intThe port the proxy token is scoped to.
proxy_mint_count
Section titled “proxy_mint_count”proxy_mint_count: int | NoneHow many proxy tokens this session has minted, or None for a direct session.
Exposed because it is the only observable that distinguishes a client which
re-minted after a resume from one that kept a stale token (STATE-8), and a harness
asserting on that behaviour needs to be able to read it. The token itself is
not exposed and cannot be: the core’s ProxyToken has no Display, no as_str,
and no Deref, so “treat authToken as a string” is as inexpressible here as it
is there (TRAP-7).
Methods
Section titled “Methods”attach
Section titled “attach”@staticmethoddef attach( region: Region, microvm_id: str, endpoint: str, agent_token: str, *, port: SupportsIndex | None = None, request_timeout: SupportsFloat | SupportsIndex | None = None,) -> SessionReattach using a private control record, without bootstrapping again.
AWS credentials mint fresh proxy tokens. This session owns its transport and
shares no sandbox lock; supervisors should attach separately for keepalives,
with a short request_timeout. Never publish or log agent_token.
attach_async
Section titled “attach_async”@staticmethoddef attach_async( region: Region, microvm_id: str, endpoint: str, agent_token: str, *, port: SupportsIndex | None = None, request_timeout: SupportsFloat | SupportsIndex | None = None,) -> SessionThe awaitable twin of Session.attach.
connect_headers
Section titled “connect_headers”def connect_headers(port: SupportsIndex) -> dict[str, str]Both proxy headers for port, so a caller can open its own connection.
A dict[str, str], for pairing with endpoint when something outside this client
opens a socket to a port on this VM. Minted through the session’s existing token
cache, so this does not burn a second control-plane call and does not open a second
refresh schedule (TRAP-9).
Empty for a direct session, which is the true answer rather than a missing one: a daemon reached directly takes no proxy headers.
The auth value is a bearer credential and this returns it. Nothing here logs or stores it, and no method takes a header map — so a caller cannot feed a forged or expired one back in.
connect_headers_async
Section titled “connect_headers_async”def connect_headers_async(port: SupportsIndex) -> dict[str, str]The awaitable twin of connect_headers.
connect_subprotocols
Section titled “connect_subprotocols”def connect_subprotocols(port: SupportsIndex) -> list[str] | NoneThe three WebSocket subprotocols for port, in the order a handshake offers them.
A MicroVM endpoint takes the auth and the target port as Sec-WebSocket-Protocol
values rather than as headers, because the browser WebSocket constructor cannot set
a header — and the platform strips all three before forwarding, so a server inside
the VM never negotiates them.
None for a direct session, and deliberately not an empty list: the subprotocol form
exists only for a request through the endpoint proxy, so a list carrying the base
value with no token would open a handshake refused for a reason naming neither the
token nor the port.
The middle string carries the credential. Same rule as connect_headers.
connect_subprotocols_async
Section titled “connect_subprotocols_async”def connect_subprotocols_async(port: SupportsIndex) -> list[str] | NoneThe awaitable twin of connect_subprotocols.
direct
Section titled “direct”@staticmethoddef direct(endpoint: str, agent_token: str) -> SessionA session against a daemon reached directly, with no proxy headers.
The shape for a local binary, a test server, or a VM reached over a tunnel. There is deliberately no constructor that takes a proxy token: minting one is the control plane’s job and it happens inside every request (TRAP-9), so a caller handing a token in would be handing in one that expires.
discovery
Section titled “discovery”def discovery() -> Discovery | NoneImage configuration, or None if this daemon predates discovery.
discovery_async
Section titled “discovery_async”def discovery_async() -> Discovery | NoneThe awaitable twin of discovery.
download_dir
Section titled “download_dir”def download_dir( remote: str, local_dir: str | PathLike[str], globs: SupportsGetItem[int, str],) -> list[DownloadedFile]Brings the files of a directory in the VM back under local_dir: the regular files
globs select, and nothing else.
The daemon packs remote, and the archive describes the VM’s filesystem, where
untrusted work runs, so core writes only regular-file members that match a glob, never
under .git whatever the globs say, and never outside local_dir. A symlink, a special
file or a ../ member is skipped, not refused. ["**"] brings every regular file back.
Returns what was written. A local directory that can’t be written to raises
InvalidArgError.
download_dir_async
Section titled “download_dir_async”def download_dir_async( remote: str, local_dir: str | PathLike[str], globs: SupportsGetItem[int, str],) -> list[DownloadedFile]The awaitable twin of download_dir. The local writes run on the shared runtime, not
on the event loop.
download_file
Section titled “download_file”def download_file( path: str, *, start_line: SupportsIndex | None = None, end_line: SupportsIndex | None = None,) -> bytesReads one file, or lines start_line through end_line of it.
The range is 1-based and inclusive, and the daemon slices the file, so reading lines
40 to 60 of a large log reads those lines alone. Either bound may be None (line 1,
through EOF), and an end_line past the last line reads through EOF. Line 0 and an end
before the start raise InvalidArgError before any request.
download_file_async
Section titled “download_file_async”def download_file_async( path: str, *, start_line: SupportsIndex | None = None, end_line: SupportsIndex | None = None,) -> bytesThe awaitable twin of download_file.
download_tar
Section titled “download_tar”def download_tar(remote: str) -> bytesThe raw tar bytes of a remote tree.
download_tar_async
Section titled “download_tar_async”def download_tar_async(remote: str) -> bytesThe awaitable twin of download_tar.
def exec(exec_id: str) -> ExecHandleA handle for an exec started earlier, possibly by another process.
The reattach path. Nothing is checked against the daemon here — the handle is an id plus a transport, and a poll is what discovers whether the exec exists.
file_exists
Section titled “file_exists”def file_exists(path: str) -> boolWhether a path exists, distinguishing absence from every other refusal.
file_exists_async
Section titled “file_exists_async”def file_exists_async(path: str) -> boolThe awaitable twin of file_exists.
health
Section titled “health”def health() -> HealthUnauthenticated liveness.
health_async
Section titled “health_async”def health_async() -> HealthThe awaitable twin of health.
keep_awake
Section titled “keep_awake”def keep_awake( interval: SupportsFloat | SupportsIndex | None = None, *, while_busy: bool = False, max_duration: SupportsFloat | SupportsIndex | None = None, idle_window: SupportsFloat | SupportsIndex | None = None, tolerated_errors: SupportsIndex | None = None,) -> KeepAwakeKeeps the VM awake by polling health from this process until stopped.
The platform counts only inbound requests as activity, so an exec working with no
client traffic is suspended once maxIdleDurationSeconds passes. This polls
/v1/health every interval seconds (default: a third of the idle window, at most
20) on a background task and returns at once. while_busy ends it once no exec is
running; max_duration ends it after that many seconds. idle_window is the VM’s
maxIdleDurationSeconds: a sandbox-held session knows it, an attached one assumes
the platform minimum of 60, and interval may be at most half of it.
tolerated_errors is how many retryable poll failures in a row it retries, a second
apart, before it ends with the error; omitted, it’s the core’s
DEFAULT_TOLERATED_ERRORS.
On a sandbox-held session a suspend or terminate through the sandbox ends the keepalive before its next poll. Stop it before suspending through anything else, or the next poll auto-resumes the VM. Dropping the returned handle stops it.
def kill(exec_id: str) -> boolSignals an exec’s whole process group. Returns whether anything was signalled.
kill_async
Section titled “kill_async”def kill_async(exec_id: str) -> boolThe awaitable twin of kill.
port_forward
Section titled “port_forward”def port_forward( guest_port: SupportsIndex, *, bind: str | None = None, max_connections: SupportsIndex | None = None,) -> PortForwardServes a local port as an HTTP and WebSocket forward to guest_port in the VM, on a
background task, and returns its handle at once: microvm port-forward’s loop.
Connections are served at once rather than one after another, so a slow request
doesn’t hold the next. A request the endpoint proxy refuses is listed in the report
with its status while the forward keeps serving. bind and max_connections are
tunnel’s. Dropping the handle stops the forward.
port_forward_async
Section titled “port_forward_async”def port_forward_async( guest_port: SupportsIndex, *, bind: str | None = None, max_connections: SupportsIndex | None = None,) -> PortForwardThe awaitable twin of port_forward, for tunnel_async’s reason.
def procs() -> list[ProcGroup]Process accounting: every registered exec with its group’s live pids.
The daemon reads /proc itself, so this needs no ps in the guest. A ProcGroup
with child_exited and a non-empty pids is a command that finished while
something it backgrounded did not; pass its exec_id to kill.
procs_async
Section titled “procs_async”def procs_async() -> list[ProcGroup]The awaitable twin of procs.
def run( command: SupportsGetItem[int, str] | str, *, shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, stdin: bool = False, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False,) -> ExecHandleStarts a command and returns its handle. Does not wait.
command is a list, or a string that becomes a one-element argv — never
whitespace-split. shell=True wants a single script string for /bin/sh -c;
shell="bash" runs it under a shell the daemon resolves in the guest, and a shell
the guest does not have is refused (unknown_shell) before anything starts.
user and group are a numeric id or a name the daemon resolves against the
guest’s /etc/passwd and /etc/group; an unknown name is refused (unknown_user,
unknown_group) before anything starts. A user with a passwd row gets HOME,
USER and LOGNAME from it, beneath the launch environment and env.
inherit_image_env starts the child’s environment from the image’s ENV (minus
AGENTD_*, never the token), beneath everything else; off by default, which keeps
the child’s environment exactly the launch environment plus env.
reap_group_on_exit asks the daemon to signal the whole process group once the
command’s own child exits, so nothing it backgrounded outlives it; off by default,
which keeps the backgrounded-grandchild-output guarantee for callers who rely on it.
poweroff_on_exit asks a supporting daemon to power off the whole guest after
the original process group has no live members. Other work ends too, and the
start acknowledgment or result can be lost. It does not keep an idle VM awake.
run_async
Section titled “run_async”def run_async( command: SupportsGetItem[int, str] | str, *, shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, stdin: bool = False, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False,) -> ExecHandleThe awaitable twin of run, with its keywords. Cancelling it before the daemon
answers may leave the exec started, under the exec_id the call was given or minted;
Session.exec(exec_id) reaches it, which is why a caller that cancels passes one.
run_sync
Section titled “run_sync”def run_sync( command: SupportsGetItem[int, str] | str, *, timeout: SupportsFloat | SupportsIndex = ..., shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, stdin: bool = False, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False,) -> ExecResultStart, wait, ack. The one-shot shape, for when output is all you want.
run_sync_async
Section titled “run_sync_async”def run_sync_async( command: SupportsGetItem[int, str] | str, *, timeout: SupportsFloat | SupportsIndex = ..., shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, stdin: bool = False, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False,) -> ExecResultThe awaitable twin of run_sync, with its keywords. Cancelling it stops the wait,
as a timeout would: the exec keeps running and its output stays until acked.
run_to_completion
Section titled “run_to_completion”def run_to_completion( command: SupportsGetItem[int, str] | str, *, on_output: Any | None = None, shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False, client_grace_sec: SupportsFloat | SupportsIndex = ...,) -> ExecResultStart, stream, and collect one command: exactly one ExecResult back (BIND-6..10).
With on_output, each OutputChunk is handed to it as it arrives. The result then
comes from the ack that follows the terminal exit event, or, when the stream ends
without one, from a wait and ack. When timeout_sec + client_grace_sec passes first
(or, with no timeout_sec, the VM’s maximum lifetime), the process group is killed
and the exec waited for and acked within client_grace_sec once more; if that fails
too the result is synthesized with posix_exit_code 124. posix_exit_code and
notes say what ended the command.
An exception from on_output stops delivery; the exec is still waited for and acked
so nothing is left behind, and then the exception is re-raised. shell, user,
group, reap_group_on_exit, poweroff_on_exit and inherit_image_env mean what they mean on run():
shell="bash" with a script string runs it under bash, which dash-based images need for
pipefail.
run_to_completion_async
Section titled “run_to_completion_async”def run_to_completion_async( command: SupportsGetItem[int, str] | str, *, on_output: Any | None = None, shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False, client_grace_sec: SupportsFloat | SupportsIndex = ...,) -> ExecResultThe awaitable twin of run_to_completion, with its keywords.
on_output is a plain function, called on the event loop’s thread between the
coroutine’s steps, one chunk at a time: the drive on the shared runtime waits for each
call to return before it reads on, so a slow callback slows the stream rather than
buffering it. An exception from it stops delivery and is re-raised once the exec is
waited for and acked, as in run_to_completion. Cancelling the call stops the drive and
leaves the exec running in the VM.
def spawn( command: SupportsGetItem[int, str] | str, *, shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, stdin: bool = False, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False, offset: SupportsIndex = 0, reconnect: bool = True, max_reconnects: SupportsIndex | None = None, idle_timeout: SupportsFloat | SupportsIndex | None = None, gap_policy: str | None = None,) -> ExecProcessStarts a command and returns it as two byte iterators, a wait(), and a kill().
The process shape, as against run’s handle: the same start request and keyword
arguments, so spawn and run with one exec_id address one server-side child.
proc.stdout and proc.stderr iterate bytes, split out of the one stream the
daemon sends, which reconnects at the byte cursor after a cut, so a suspend and resume
doesn’t end them early. Read both sides, from two threads when a command writes much
to both: each holds one unread chunk, like a pipe.
gap_policy is what an evicted byte range does. "error", the default when it’s
None, raises PlatformError (wire kind OutputGap) from both iterators naming the
range, since the wire can’t say which side lost the bytes; "event" records it on
proc.gaps and keeps both going. offset, reconnect, max_reconnects and
idle_timeout are ExecHandle.stream()’s.
spawn_async
Section titled “spawn_async”def spawn_async( command: SupportsGetItem[int, str] | str, *, shell: bool | str = ..., cwd: str | None = None, env: dict[str, str] | None = None, user: SupportsIndex | str | None = None, group: SupportsIndex | str | None = None, timeout_sec: SupportsFloat | SupportsIndex | None = None, stdin: bool = False, exec_id: str | None = None, reap_group_on_exit: bool = False, poweroff_on_exit: bool = False, inherit_image_env: bool = False, offset: SupportsIndex = 0, reconnect: bool = True, max_reconnects: SupportsIndex | None = None, idle_timeout: SupportsFloat | SupportsIndex | None = None, gap_policy: str | None = None,) -> ExecProcessThe awaitable twin of spawn, with its keywords. The process it answers iterates
with async for as well as for; cancelling the call is run_async’s.
sync_dir
Section titled “sync_dir”def sync_dir( local_dir: str | PathLike[str], *, full: bool = False, delete_timeout: SupportsFloat | SupportsIndex | None = None,) -> SyncReportSyncs local_dir into the VM’s /workspace once, uploading only what changed.
Core’s one pass, microvm sync’s: the local tree is hashed and diffed against the
manifest the last sync left in the VM, the changed members travel as one archive, the
paths gone locally are removed in the VM with one rm whose deadline is
delete_timeout (core’s default when None), and the manifest is rewritten. full=True
ignores the manifest and uploads everything. .git, target, node_modules and
.venv never travel. A tree over the daemon’s budgets raises InvalidArgError before
anything is sent.
sync_dir_async
Section titled “sync_dir_async”def sync_dir_async( local_dir: str | PathLike[str], *, full: bool = False, delete_timeout: SupportsFloat | SupportsIndex | None = None,) -> SyncReportThe awaitable twin of sync_dir. The hashing and the local reads run on the shared
runtime, not on the event loop.
tunnel
Section titled “tunnel”def tunnel( guest_port: SupportsIndex, *, bind: str | None = None, verify_identity: TunnelIdentity | None = None, max_connections: SupportsIndex | None = None,) -> TunnelServes a local TCP port as a tunnel to guest_port in the VM, on a background task,
and returns its handle at once: microvm tunnel’s loop.
Each local connection gets a WebSocket of its own through the endpoint proxy, and a
connection the daemon refuses is listed in the report while the tunnel keeps serving.
bind is a host:port to listen on, loopback on a port the OS picks by default, and
the handle’s local_address says which. max_connections stops accepting after that
many. With verify_identity (a TunnelIdentity, such as Sandbox.tunnel_identity),
each connection first proves the far end is the daemon of the VM that identity was
launched with, and a connection that can’t is refused.
The tunnel carries this session’s credentials to whoever connects, so bind beyond loopback only on a network you trust. Dropping the handle stops the tunnel.
tunnel_async
Section titled “tunnel_async”def tunnel_async( guest_port: SupportsIndex, *, bind: str | None = None, verify_identity: TunnelIdentity | None = None, max_connections: SupportsIndex | None = None,) -> TunnelThe awaitable twin of tunnel: binds the listener on the shared runtime and answers
the same handle, whose loop runs there either way.
upload_file
Section titled “upload_file”def upload_file(path: str, data: bytes, *, mode: str | None = None) -> NoneWrites one file, creating parents. mode is an octal string ("0755"), which
is the daemon’s shape — an integer here would be ambiguous between 0o755 and 755.
upload_file_async
Section titled “upload_file_async”def upload_file_async(path: str, data: bytes, *, mode: str | None = None) -> NoneThe awaitable twin of upload_file.
upload_tar
Section titled “upload_tar”def upload_tar(remote: str, archive: bytes) -> NoneExtracts pre-built tar bytes under remote.
Bytes rather than a local path: packing a directory is the caller’s, because the symlink and permission decisions in a pack belong to whoever knows what the tree means.
upload_tar_async
Section titled “upload_tar_async”def upload_tar_async(remote: str, archive: bytes) -> NoneThe awaitable twin of upload_tar.
wait_until_ready
Section titled “wait_until_ready”def wait_until_ready(timeout: SupportsFloat | SupportsIndex = ...) -> HealthPolls health until the daemon reports bootstrapped.
Connection errors on the way are expected rather than exceptional: a VM that has just reached RUNNING commonly refuses a connection or two before the proxy path is wired up. A fatal error ends the wait at once, because retrying a 401 until the deadline is the mistake the retryable split exists to prevent.
wait_until_ready_async
Section titled “wait_until_ready_async”def wait_until_ready_async(timeout: SupportsFloat | SupportsIndex = ...) -> HealthThe awaitable twin of wait_until_ready.
Special methods
Section titled “Special methods”__repr__
Section titled “__repr__”def __repr__() -> strProvenance
Section titled “Provenance”This page is generated from bindings/microvms-py/microvms.pyi by Griffe 2.3.0, run from site/scripts/gen-reference.mjs on every pnpm run sync, so an edit made here is overwritten by the next run.
To change the page, change the doc comment in the binding’s Rust source, then regenerate the declarations with mise run stubs. mise run stubs:check fails when the committed file no longer matches the source.