Skip to content

Go library

Last updated: 2026-09-06

New to the library? Start with the library overview or the smallest useful Go program. This page is the package reference.

Most programs want exactly this: boot a microVM from an OCI image, run a command inside it, read the output. workspace.Run does all of it in one call:

package main
import (
"context"
"fmt"
"github.com/geoffbelknap/microagent/pkg/workspace"
)
func main() {
opts := workspace.DefaultOptions()
opts.Name = "demo-vm"
opts.ImageRef = "docker.io/library/ubuntu:24.04"
opts.ExecCommand = "uname -a"
result, err := workspace.Run(context.Background(), opts)
if err != nil {
panic(err)
}
if result.Result != nil {
fmt.Print(result.Result.Stdout)
}
}

DefaultOptions picks the host backend, kernel, and state directory; you set only what your program cares about. The rest of this page covers the packages behind this call and the lower-level APIs around it.

The library doesn’t require agent semantics. The same packages back the CLI’s agent-flavored workflows and any program that just wants microVMs: build a rootfs from an OCI image, boot a VM, run a command, tear it down. The high-level pkg/workspace API treats every workspace as a workload-role identity by default. You get caller-visible identity for free without writing agent-aware code, and you can drop down to pkg/vmkit when you need a different role or a custom supervisor request.

These are the core packages — the ones most embedding programs import first:

PackagePurpose
pkg/vmkitsupervisor request/response types, validation, and executable supervisor client
pkg/workspaceworkspace lifecycle API, options, defaults, request construction, backend supervisor selection, and shared helpers
pkg/operationstable operation error categories shared by library, CLI, and MCP adapters
pkg/kernelkernel default manifest, install, verify, update checks, and support checks
pkg/imagecachereusable rootfs image cache indexing, pull, tag, remove, and prune
pkg/diagnosticsbackend host diagnostics and support summaries
pkg/perfcold, restore, fork, resume, interactive, footprint, and steady-state performance measurements
pkg/rootfsOCI image and tar bundle conversion into ext4 disks
pkg/supervisors/firecrackerLinux Firecracker supervisor implementation

A second tier of supporting packages backs specific CLI workflows. Import them when the CLI ↔ library mapping table at the bottom of this page points at them:

PackagePurpose
pkg/workspace/exec/protocolthe structured exec wire protocol (ExecRequest, ExecResult, ExecStatus); every workspace.Exec caller imports this
pkg/workspace/exec/clienthost-side client for the guest structured exec service (used internally by workspace.Exec; import it only for custom transports)
pkg/scaffoldgenerates a starter agent project (microagent.yaml plus supporting files); backs microagent init
pkg/commitsnapshots a stopped workspace’s rootfs back into an OCI image and pushes it; backs microagent commit / microagent image push
pkg/modelmanages local GGUF model files pulled from Hugging Face (pull, list, remove, prune)
pkg/modelrunnermanages host-local model server processes (llama.cpp, vLLM, or custom commands); modelrunner.Ensure starts or reuses a runner
pkg/modelserviceattaches model runners through a stable host endpoint with optional HTTP mediation
pkg/volumeuser-defined named volumes: VM-independent ext4 disks created, attached, and removed by name
pkg/secretresolves scheme-prefixed secret references (env:/file:/dotenv:/vault:/helper:) to values held host-side only
pkg/registryauthOCI registry credential login, logout, and listing without a Docker dependency

The CLI is an adapter over these packages. Go callers should use the library directly for workspace lifecycle operations instead of shelling out to microagent.

These exported symbols are part of the documented Go API. Helper functions and backend plumbing can remain exported for package boundaries without being promoted here, but caller-facing symbols should be added to this page when they are introduced.

PackageDocumented symbols
pkg/operationErrorKind, Error, New, Wrap, IsKind, ProgressStatus, ProgressRunning, ProgressSucceeded, ProgressFailed, ProgressCanceled, ProgressEvent, ProgressFunc
pkg/vmkitRequest, Response, DatapathStartupFailure, Config, Identity, Disk, NetworkConfig, PortForward, MediationConfig, VsockListener, RuntimeArtifacts, ArtifactRef, RuntimeResult, Event, VMState, StateUnknown, RoleWorkload, Supervisor, SupervisorClient, ExecutableSupervisor, NewRuntimeContract, FeatureContract, OperationContract, OperationID, OperationEffect, OperationIdempotency, OperationConfirmation, OperationSideEffect, OperationTypeID, OperationEffectRead, OperationEffectMutation, OperationEffectDestructive, OperationIdempotencyReadOnly, OperationIdempotencyReplayable, OperationIdempotencyKeyedReplay, OperationIdempotencyNotIdempotent, OperationConfirmationPreview, OperationSideEffectHostState, OperationSideEffectWorkspaceState, OperationWorkspaceDispatch, OperationWorkspaceExec, OperationWorkspaceConsole, OperationWorkspaceResult, OperationWorkspaceLogs, OperationWorkspaceEvents, OperationWorkspaceStats, OperationWorkspaceEgress, OperationWorkspaceCost, OperationWorkspaceObserve, OperationWorkspaceCreate, OperationWorkspaceStart, OperationWorkspaceInspect, OperationWorkspaceWait, OperationWorkspaceStop, OperationWorkspaceHalt, OperationWorkspaceKill, OperationWorkspaceQuarantine, OperationWorkspaceDelete, OperationWorkspaceList, OperationWorkspaceClone, OperationFileCopyOffline, OperationFileCopyLive, OperationArtifactList, OperationArtifactGet, OperationArtifactRead, OperationWorkspaceCommit, OperationWorkspaceApply, OperationNetworkPublish, OperationNetworkApplyLive, OperationNetworkInspect, OperationWorkspacePause, OperationWorkspaceResume, OperationSnapshotCreate, OperationSnapshotRestore, OperationSnapshotFork, OperationSnapshotList, OperationSnapshotDelete, OperationSnapshotCatalog, OperationVolumeCreate, OperationVolumeList, OperationVolumeInspect, OperationVolumeDelete, OperationVolumeResize, OperationWorkspaceResize, FeatureCapabilityResize, OperationImagePull, OperationImageList, OperationImagePush, OperationImageTag, OperationImageDelete, OperationImagePrune, OperationModelPull, OperationModelList, OperationModelRemove, OperationModelPrune, OperationModelServe, OperationModelStop, OperationModelRunners, OperationModelPolicyCheck, OperationModelPolicyEval, OperationKernelInstall, OperationKernelVerify, OperationKernelList, OperationKernelCheck, OperationRootfsBuild, OperationHostInspect, OperationDoctorCheck, OperationProfilesList, OperationContractGet, OperationDescribe, OperationProjectInit, OperationSecretCheck, OperationSecretAudit, OperationPerfBoot, OperationPerfReady, OperationPerfFootprint, OperationPerfSteady, OperationSupervise, OperationBrokerConfigure, OperationRegistryLogin, OperationRegistryLogout, OperationRegistryList, OperationServeMCP, OperationHostGC, OperationPing, FeatureScope, FeatureBackendNeutral, FeatureCapability, FeatureCapabilityStructuredExec, FeatureCapabilityNetworkPublish, FeatureCapabilityOfflineFileCopy, FeatureCapabilityLiveFileCopy, FeatureCapabilityEgressMediation, CapabilityTier, CapabilityTierCore, CapabilityTierSafety, CapabilityTierFeature, CapabilityTierOf, VerdictOK, VerdictDegraded, VerdictFailed, FeatureBackend, FeatureGap, UnsupportedFeatureError, FeatureContracts, OperationContracts, FeatureBackendSupport, BackendSupportsFeature, BackendSupportsOperation, FeatureForCLICommand, FeatureForMCPTool, OperationForCLICommand, OperationForMCPTool, OperationContractByID, NewUnsupportedFeatureError, NewUnsupportedFeatureCapabilityError, NewUnsupportedOperationError, ContractDurability, ContractDurabilityTier, ContractDurabilityTransition, DurabilityTier, DurabilityRuntime, DurabilityWorkspace, DurabilitySnapshot, DurabilityIndependent, DurabilityEffect, DurabilityPreserved, DurabilityDiscarded, DurabilityCaptured, DurabilityRestored, DurabilityCopied, DurabilityReset, DurabilityRemoved, DurabilityNotGuaranteed, DurabilityContract, ContractPersistence, ContractPersistenceTier, PersistedArtifact, PersistenceTier, PersistenceRecoverable, PersistenceOperational, PersistenceAudit, PersistenceEvidence, PersistenceContract, IsKnownBackend, Capabilities, BackendCapabilities, EgressDatapathBinEnv, ResolveEgressDatapathBin, SnapshotManifest, SnapshotArtifact, SnapshotInfo, SnapshotManifestName, SnapshotVMStateName, SnapshotMemoryName, SnapshotRootfsName, SnapshotAppleVFMachineState, SnapshotAppleVFConfig, SnapshotsDir, SnapshotDir, SnapshotStagingParent, PublishSnapshotDir, SnapshotRootfsArtifact, SnapshotMachineStateArtifacts, FirecrackerSnapshotArtifacts, AppleVFSnapshotArtifacts, WriteSnapshotManifest, ReadSnapshotManifest, ListSnapshots, RemoveSnapshot, MaterializedSecretsDeclared, ValidateSnapshotSecretCapture, ValidateSnapshotSecretRestore, EgressModeBroker, EgressModeMITM, EgressModeOff, EgressMediationOn, EgressModeForgesCerts, NetworkModeMediates, ValidateEgressMode, ResolveEgressModeDefault, EgressPolicy, EgressCaps, NormalizeEgressPolicy, ReadinessSignal, RuntimeReadiness, MediationReadinessSignal, BrokerConfig, BrokerAssurance, BrokerAssuranceSemantic, BrokerAssuranceTrustedUpstream, BrokerGrant, BrokerOperationGrant, BrokerValueGrant, BrokerBodyGrant, BrokerJSONSchema, BrokerResponseGrant, BrokerRedirectGrant, BrokerEffect, BrokerEffectRead, BrokerEffectWrite, ValidateBrokerSecurity, BrokerListenerTarget, ValidateBackendVsockListeners, GuestBootParam, GuestBootParams, AppleVFUndecodedConfigFields
pkg/modelserviceOptions, Attachment, Attach, Release, UpstreamResolver, PairOptions, Pair, PendingRelease
pkg/workspaceOptions, OptionsFromRequest, EgressPolicyFromOptions, DefaultOptions, Spec, SpecApplyOptions, ApplyResult, Manifest, CapabilityComposition, EvaluateCapabilityComposition, ModelRunnerSpec, ModelMediationSpec, Result, GuestResult, CopyResult, ListEntry, SuperviseOptions, SuperviseResult, ConsoleOptions, ShellTarget, ConsoleReadTimeoutError, ConsoleCompletionUnknownError, ShellReadinessProbeMode, ShellReadinessProbeTCP, ShellReadinessSignalWithMode, DefaultModelGuestPort, ExecReadyProbeTimeout, ExecReadyWait, ExecMaxTransientRetries, CleanStopSyncTimeout, ExecPort, ExecPortForName, ExecRetryExhaustedError, ExecRetryMetadata, ExecReadinessSignal, Create, CreateFromSnapshot, Run, RandomName, Start, Inspect, Status, Wait, WaitOptions, WaitResult, WaitTimeoutError, WaitStateOK, IsWaitTerminalState, ResultStatus, GC, GCResult, GCReap, GCFailure, ArtifactsFor, GetArtifact, ArtifactGetOptions, GetArtifactWithOptions, Copy, CopyOptions, CopyWithOptions, GuestRootfsLayerTar, Clone, CloneOptions, CloneWithOptions, ReadLogs, ReadSupervisorLogs, ReadEvents, EventsPath, ReadEgressAudit, EgressAuditPath, ReadBrokerAccess, BrokerAccessPath, MergeEgressEvents, EgressEvent, AuditIntegrityError, EgressAuditSummary, SummarizeEgressAudit, RunDispatch, DispatchResult, SampleStats, Stats, Network, List, Control, Pause, Resume, DefaultSnapshotTag, DefaultForensicSnapshotTag, Snapshot, SnapshotForensic, SnapshotList, SnapshotRemove, Apply, Exec, ExecWithMetadata, ExecStream, MarkActivity, IsRetryableExecTransient, DialConsole, WaitConsoleCommandReady, SendConsoleCommand, ConsoleTarget, ProbeShellCommand, Supervise, ReadSpec, ApplySpec, ApplySpecFile, ReadManifest, WriteManifest, ProfileNames, LookupProfile, NormalizeArch, ValidateArch, WorkspaceNotFoundError, Supervisor, FirecrackerSupervisorPathFromExecutable, LookupE2fsprogsTool, Mke2fsPath, DebugfsPath, Resize2fsPath, Resize, ResizeOptions, ResizeResult, KernelInstaller, ProgressKernelInstaller, RegisterKernelInstaller, RegisterProgressKernelInstaller, EnsureKernel, ShellReadinessProbeCommand, BrokerSecurityOptions, ParseBrokerConfig, ParseBrokerEndpoints
pkg/kernelInstallOptions, InstallResult, Install, VerifyOptions, VerifyResult, Verify, DefaultSource, Support, CheckUpdate
pkg/imagecachePullOptions, PruneOptions, Record, PruneResult, Pull, Find, List, Tag, Remove, Prune, PruneWithOptions, ReadIndex, FromProvenance
pkg/diagnosticsOptions, Check, DeriveVerdict, EgressTProxyRemediation
pkg/perfBootOptions, BootReport, BootProgressPhase, BootProgressWorkspace, BootProgressTeardown, BootProgressComplete, BootProgressEvent, BootProgressFunc, MeasurementBoundary, ReadyOptions, ReadyStartMode, ReadyStartColdBoot, ReadyStartSnapshotFork, ReadyStartSnapshotRestore, ReadyStartPausedResume, ReadyProbeMode, ReadyProbeStructuredExec, ReadyProbeInteractiveShell, ReadyReport, ReadyBoundary, ReadySetup, ReadyWarmup, ReadyIteration, ReadyPhases, ReadySummary, ReadyProgressRun, ReadyProgressSetup, ReadyProgressWarmup, ReadyProgressMeasurement, ReadyProgressPhase, ReadyProgressWorkspacePrepare, ReadyProgressLifecycle, ReadyProgressInterface, ReadyProgressProbe, ReadyProgressTeardown, ReadyProgressComplete, ReadyProgressEvent, ReadyProgressFunc, Distribution, FootprintReport, SteadyOptions, SteadyReport, SteadyProgressEvent, SteadyProgressFunc, Iteration, Summary, RSSSample, RSSSummary, RootfsSourceBaseline, RootfsSourceBuild, Boot, Ready, ParseReadyStartMode, ParseReadyProbeMode, Footprint, Steady, SteadyWithOptions, ProcessRSSKiB, ParseRSSKiB, SampleProcessRSS, SummarizeIterations, SummarizeReadyIterations, SummarizeRSSSamples
pkg/rootfsBuildRequest, BundleRequest, BundleProvenance, Builder, ErrExtractionLimit, NewBuilder, NormalizeRequest, NormalizeBundleRequest, Platform, Provenance
pkg/supervisors/firecrackerSupervisor

perf.ReadyOptions.Warmups controls excluded full-path runs before measured iterations. perf.ReadyReport.Warmup records those runs separately, so they never enter ReadyReport.Summary. Set ReadyOptions.Progress to receive typed perf.ReadyProgressEvent values for setup, warm-up, measurement, and teardown phases. The callback owns presentation; the library does not write progress to a terminal.

perf.BootOptions.Progress reports disposable workspace, rootfs, teardown, and completion phases through perf.BootProgressEvent. Use perf.SteadyWithOptions when a caller needs perf.SteadyProgressEvent values for individual memory samples. The original perf.Steady function remains the compact no-callback form.

Use pkg/vmkit when you need the shared request/response schema or want to call an executable supervisor.

package main
import (
"context"
"fmt"
"github.com/geoffbelknap/microagent/pkg/vmkit"
)
func main() {
resp, err := vmkit.ExecutableSupervisor{
Path: "microagent-firecracker-supervisor",
}.Do(context.Background(), vmkit.Request{Command: "host"})
if err != nil {
panic(err)
}
fmt.Println(resp.Backend, resp.OK)
}

On Linux, Go callers can also use github.com/geoffbelknap/microagent/pkg/supervisors/firecracker directly. The package name is firecracker; alias it if you like. The req below is any vmkit.Request you construct:

import (
firecrackersupervisor "github.com/geoffbelknap/microagent/pkg/supervisors/firecracker"
)
resp, err := firecrackersupervisor.Supervisor{}.Do(ctx, req)

An application embedding pkg/workspace on macOS must set MICROAGENT_EGRESS_DATAPATH_BIN to an installed microagent CLI before it starts a mediated Apple VF workspace. The library does not assume the embedding process implements microagent’s hidden datapath command. Startup returns Response.DatapathStartupFailure when the selected executable exits early or its CA material is unavailable.

firecracker.ResolveBinaryFrom(anchor) is the one place the Firecracker VMM binary is located: MICROAGENT_FIRECRACKER, then PATH, then ../libexec/firecracker relative to anchor (normally the supervisor executable). The supervisor’s boot path and doctor’s probe both call it, so a diagnostic verdict and an actual boot can never resolve different binaries. Pass the supervisor’s path as the anchor to see exactly what a boot would use.

firecracker.ReadEgressL4DropCounts(tap) reads the cumulative datapath drop counter for a workspace’s tap and returns it as []egress.DropCount under the class firecracker.EgressL4DropClass. It is the backend half of egress.Options.DropCounters. Guest traffic with no allowlistable destination identity (IPv4 ICMP and other non-TCP/UDP L4) is dropped at the firewall and never reaches the mediator. A sampled counter is the only way those drops can be reported at all. It must be called from the workspace’s own network namespace, where those rules are visible. A missing rule is not an error — it is the ordinary state for a workspace with no mediated egress — so it returns no counts instead of failing.

For backend-independent code, depend on the interface:

func inspect(ctx context.Context, supervisor vmkit.Supervisor, req vmkit.Request) (vmkit.Response, error) {
req.Command = "inspect"
return supervisor.Do(ctx, req)
}

vmkit.NewRuntimeContract() exposes high-level feature records, lifecycle durability, the persisted-artifact catalog, and the typed operation registry shared by the CLI and MCP adapters. vmkit.PersistenceContract() classifies every microagent-owned file family as recoverable, operational, audit, or evidence and declares its permissions, writer, cleanup owner, integrity, retention, and recovery behavior. Use vmkit.OperationContracts() for stable operation identities, adapter aliases, operation-level capability requirements, and canonical request/result type IDs. Library code should resolve stable IDs with vmkit.OperationContractByID(); adapter coverage can use vmkit.OperationForCLICommand() and vmkit.OperationForMCPTool(). If a library path rejects an operation, return vmkit.NewUnsupportedOperationError() so CLI and MCP callers see the same structured error shape.

Use pkg/rootfs when your program needs to build a VM rootfs from an OCI image without shelling out to microagent rootfs.

package main
import (
"context"
"github.com/geoffbelknap/microagent/pkg/rootfs"
)
func main() {
_, err := rootfs.NewBuilder().Build(context.Background(), rootfs.BuildRequest{
ImageRef: "docker.io/library/ubuntu:24.04",
Platform: rootfs.Platform{OS: "linux", Architecture: "amd64"},
OutputPath: "/tmp/rootfs.ext4",
StateDir: "/tmp/microagent-build",
SizeMiB: 2048,
})
if err != nil {
panic(err)
}
}

rootfs.ValidateImageRef(ref) checks that a reference parses — the same normalization and parse the builder runs first, with no network or filesystem access. Call it to reject a doomed configuration before spending anything on it. workspace.Create and workspace.Run run the same check ahead of their dry-run returns, so a dry run and a real run refuse the same references with the same error.

Image and bundle extraction is bounded by the requested disk size across all layers. Auto-sized builds allow at most 32 GiB of extracted content, and every build also limits archive entry count, path depth, and header metadata. A limit violation returns an error matching rootfs.ErrExtractionLimit and removes the partial output and staging tree.

Set BuildRequest.BaseCacheDir to reuse extracted base image content across builds; rootfs.BaseCacheDirFor(stateDir) derives the standard location the CLI uses (honoring its environment override). The builder resolves the manifest digest from the source on every build and consults the cache by that digest, so a cached build and a fresh build of the same digest are byte-identical inputs. The returned Provenance.BaseSource says which happened (rootfs.BaseSourceRegistry, rootfs.BaseSourceLocalLayout, or rootfs.BaseSourceCache). rootfs.ClearBaseCache(dir, selector) removes entries (each reported as a rootfs.BaseCacheEntry) — the image cache’s delete/prune purge path is its main caller.

Builds strip setuid/setgid bits from the image by default; set BuildRequest.AllowGuestSetuid to preserve them for images that need a non-root user with working sudo. Provenance.SetuidPolicy records which happened (rootfs.SetuidPolicyStripped or rootfs.SetuidPolicyPreserved), with the removed paths in SetuidStripped and the uncapped total in SetuidStrippedCount. The policy keys the base-stage cache, so the two variants never share extracted trees.

rootfs.BuildRequest.DebugfsPath selects the e2fsprogs debugfs binary used to apply OCI inode metadata after the ext4 image is created. The returned rootfs.Provenance.ImageDefaults is a rootfs.ImageDefaults value containing the image user, environment, entrypoint/command, working directory, stop signal, exposed ports, volumes, and labels. Status responses expose that same shape as vmkit.OCIImageDefaults so persisted and inspected values stay aligned.

Use pkg/workspace when your program wants to create, run, start, inspect, and control named workspaces without parsing CLI flags.

workspace.DefaultOptions() picks the host backend (Firecracker on Linux or Apple Virtualization.framework on macOS), guest architecture, default kernel path, and default state directory. You override only what your program needs. The common pattern example at the top of this page shows the canonical DefaultOptions + Run call.

Leave Options.Name empty and Run mints a readable, collision-safe name via RandomName (for example run-brave-otter-4f9c); RunDispatch does the same with a dispatch- prefix. RandomName(prefix) is exported for programs that want the same naming for workspaces they create themselves.

Result.Result is a *GuestResult with Stdout, Stderr, and ExitCode captured from the guest. Result.Response carries the supervisor’s structured response (state, identity, verification).

Status responses expose declared egress coverage through Response.EgressCapture. When the backend can observe its mediator process, EgressCapture.Live is non-nil and reports current liveness; nil means the backend did not make a liveness observation. Quiescent workspace states also recompute and enforce the recorded rootfs hash, while running workspaces measure it without treating expected guest writes as divergence. EgressCapture.EncryptedDNS is an EgressEncryptedDNSCoverage value. It is EgressEncryptedDNSDeniedHTTP1 for mitm, where recognizable HTTP/1 DNS requests are denied, and EgressEncryptedDNSOpaque for broker, where TLS request content is not observable.

workspace.Run has three behaviors worth knowing before you ship:

  • The run phase is bounded by Options.Timeout. DefaultOptions sets it to workspace.DefaultTimeout (5 minutes). The rootfs build and image pull run first, under your own ctx; Run then wraps Options.Timeout around the supervisor run — the boot and your guest command. A guest command that legitimately needs more than 5 minutes (a compile, a large in-guest download) is killed at the deadline. Raise Options.Timeout for long-running commands; the tighter of it and the parent ctx deadline wins.
  • Cleanup happens only on success. When the run completes and the supervisor reports OK, Run removes the scratch state — unless Options.Keep is set. A run that fails (boot error, supervisor error, timeout) deliberately leaves its state directory under <StateDir>/workspaces/<name>/ for debugging. Remove it explicitly with workspace.Control(ctx, opts, "delete"), or pick a fresh name for the next attempt. run is one-shot and discards by default; Create+Start are the durable path where delete is always the explicit removal.
  • A command is required. Run returns an error when Options.ExecCommand is empty, unless Options.UseImageCommand is set to run the OCI image’s own entrypoint/command instead. With an empty Options.Name, Run generates a unique run-<timestamp> name; with an empty Options.ImageRef it falls back to the default per-architecture Python image.

workspace.Options is a plain value struct — copy it freely; each call gets its own copy. The exported fields, grouped by concern:

Workspace identity and image

FieldMeaning
Nameworkspace name; becomes the RuntimeID in requests, state paths, and events
ImageRefOCI image reference the rootfs is built from
ImageDefaultspersisted rootfs.ImageDefaults applied to normal workload boots and reported by status
Hostnameguest hostname
Architectureguest architecture (amd64/arm64)
Backendbackend id; must match the host backend (ValidateHostBackend)
Profile / ProfileExplicitnamed resource profile (tiny/small/medium/large) and whether it was set explicitly

Command and lifecycle

FieldMeaning
ExecCommandone-shot command Run executes in the guest
UseImageCommandrun the image’s own entrypoint/command instead of ExecCommand
ServiceCommandlong-running service command for durable workspaces
Entrypointentrypoint override
SetupCommandscommands run once during rootfs preparation
ConsoleShellabsolute guest path of the interactive console shell
RestartPolicyrestart policy for Supervise (default never)
Healthhealth-check declaration
Timeoutrun deadline (default 5 minutes; see the lifecycle contract above)
LeaseSecondslifetime lease measured from VM start; activity does not renew it. Create/CreateFromSnapshot default this to DefaultLeaseSeconds (7 days) unless LeaseSecondsExplicit is set — including an explicit 0, which still means permanent
Keepretain scratch state after a successful Run
SerialLogMaxBytesbytes of console log inlined in Result.SerialLog as a tail (0 = workspace.DefaultSerialLogMaxBytes, 8192; negative = full log). Result.SerialLogBytes/SerialLogTruncated report the full size and whether the inline copy is an excerpt; the full log stays at Result.SerialPath while the workspace is kept
DryRunvalidate and prepare without booting
PrepareForStartprepare state for a later Start
FromSnapshotrestore in place from this snapshot tag on Start
MaintenanceBootboot with only shell/exec channels (no service, no secrets) for file operations
SerialInputenable serial console input

Resources and network

FieldMeaning
MemoryMiB, CPUCount, SizeMiBexplicit resource sizing (override the profile)
SpecMemory, SpecCPU, SpecSizemark which resources came from an explicit spec
Networkvmkit.NetworkConfig: mode (user default), port forwards, DNS, routes. A forward bound to a concrete IPv4 Host preserves that address as the guest application’s local address
Mediationoptional vmkit.MediationConfig guest-to-host mediation channel
ResultPort, ShellPort, ExecPort, GuestShellPort, GuestExecPortvsock/TCP port assignments (defaulted per workspace name)
VsockListenersextra host vsock listeners
BakedVsockUDSPathsource snapshot’s baked vsock path when starting from a snapshot

Files, disks, and outputs

FieldMeaning
Fileshost files copied into the rootfs at build time
Disksextra data disks (including named managed volumes)
Outputsdeclared egress artifacts retrievable by name with GetArtifact
Envguest environment variables

Secrets and credentials

FieldMeaning
Secretsname → scheme-prefixed reference, resolved and delivered at start
SecretEnvFilesdotenv file paths re-read on each start
OnDemandSecretslazy references, never materialized in the guest
SecretsAuditappend every secret access to the audit log
CapabilityRiskAcknowledgementoperator reason accepting a hazardous complete grant set; persisted and reported, never treated as a validation bypass
CredSwapProvidersparsed --cred-swap specs; provider keys injected host-side, never in the guest

Egress and broker

FieldMeaning
EgressModebroker (default), mitm, or off
EgressAllowallowlisted egress destination hosts
EgressPassthroughallowed hosts that are not TLS-intercepted
EgressAllowlistLockedrestrict egress to allowlisted destinations only
EgressSwapConfigPathoperator credential-swap config (host-side injection)
EgressMaxBytesPerSec, EgressMaxTotalBytes, EgressMaxConcurrentConnsper-mediator-process caps (ASK tenet 8); EgressPolicyFromOptions defaults EgressMaxTotalBytes/EgressMaxConcurrentConns to DefaultEgressMaxTotalBytes (50 GiB) / DefaultEgressMaxConcurrentConns (256) under broker/mitm unless the paired *Explicit field is set
Broker / Brokersegress broker endpoint(s); setting both is rejected — see the broker section

Bounded operations

Beyond the egress caps above, pkg/workspace bounds one more dimension by default (ASK tenet 8, operations-bounded): the host-wide workspace-count ceiling. EnsureWorkspaceCapacity fails closed at Create/CreateFromSnapshot/Start once CountActiveWorkspaces (running/starting/paused) reaches the ceiling MaxWorkspaces resolves. MaxWorkspaces also returns a MaxWorkspacesSource naming where the ceiling came from. MaxWorkspacesSourceOperator means the MaxWorkspacesEnv (MICROAGENT_MAX_WORKSPACES) environment variable is set. Otherwise it is MaxWorkspacesSourceComputed from DefaultMaxWorkspaces (detected host memory, clamped to 4-100), or MaxWorkspacesSourceFallback (10) when memory detection is unavailable. Inspect/Status attach a vmkit.BoundedOperationsStatus as Response.BoundedOperations, reporting every bound in force plus the current active-workspace count.

EvaluateCapabilityComposition derives stable categories from the complete effective options. Create, Run, snapshot forks, and Start reject the combination of guest private data, injected external content, and unmediated outbound before boot unless CapabilityRiskAcknowledgement records an operator reason. The same CapabilityComposition is returned in structured results and stored in the workspace manifest.

Model pairing

FieldMeaning
Modelcanonical model ref the workspace is paired with (persisted; re-paired each start)
ModelTargethost host:port of a paired model server or service, realized as a guest→host vsock channel
ModelTargetStablethe target owns runner reconnection; supervisors forward to that address without model lookup
ModelRunnerModelRunnerSpec: runner selection, GPU intent, backend model id, command template, args
ModelMediationModelMediationSpec: mediation mode and policy source

Advanced paths and hooks

FieldMeaning
StateDirstate root (default ~/.microagent)
KernelPath / KernelExplicitkernel image path and whether it was set explicitly
SupervisorPathsupervisor companion binary override
GuestInitPathmicroagent-guestinit binary override
Mke2fsPathmke2fs binary used for ext4 builds
DebugfsPathdebugfs binary used to apply OCI filesystem metadata; workspace.DebugfsPath resolves the packaged default
Verificationpre-computed runtime verification to attach
RootfsBaseimmutable image-store lineage for a private writable rootfs; normally populated by baseline reuse
Progressoperation.ProgressFunc callback for typed workspace and rootfs phases; the library never renders terminal output

Paired model workspaces set Options.Model, Options.ModelRunner, and Options.ModelMediation. ModelRunnerSpec stores the runner selection (llamacpp, vllm, or custom), GPU intent, backend model id, custom command template, and repeatable runner args. ModelMediationSpec stores the mediation mode, policy source (PolicyFile or PolicyURL), and an optional PolicyTimeout for policy fetches. Runner env is transient and is intentionally not persisted to workspace manifests.

Use modelservice.Pair to prepare a workspace’s model before calling Run, Create, or Start. It downloads missing models, acquires a runner hold, attaches the host service, and sets the guest model URLs. Runner and mediation settings use the same spec fields and environment defaults as the CLI.

opts := workspace.DefaultOptions()
opts.Name = "research"
opts.ImageRef = "alpine"
opts.ExecCommand = "printenv OPENAI_BASE_URL"
opts.Model = "Qwen/Qwen2.5-0.5B-Instruct-GGUF/qwen2.5-0.5b-instruct-q4_k_m.gguf"
release, err := modelservice.Pair(ctx, &opts, modelservice.PairOptions{
ExecPath: microagentPath,
})
if err != nil {
return err
}
defer release()
_, err = workspace.Run(ctx, opts)
return err

Import github.com/geoffbelknap/microagent/pkg/modelservice alongside pkg/workspace for this example. ExecPath must name a trusted microagent or microagent-model-service executable from the same version. Both implement the companion protocol. The CLI honors MICROAGENT_MODEL_SERVICE_BIN; library callers set ExecPath explicitly. PairOptions.Token optionally supplies a pull credential; otherwise the documented HuggingFace environment variables apply. The pull token is never stored in workspace state.

Pair leaves options unchanged on failure and releases resources acquired before attachment or event persistence failed. Its returned cleanup function releases the service and runner hold on a best-effort basis. With no model, Pair returns a no-op cleanup function.

For detached workspaces, keep the pairing alive after Start returns. Before halt, kill, or delete, call modelservice.PendingRelease(stateDir, name, backend) to capture cleanup; invoke the returned function after the lifecycle operation succeeds. Capturing it before deletion preserves the model reference. Pair again when starting a stopped workspace.

For an already-managed runner, modelservice.Attach accepts a modelrunner.Record and returns only the service attachment. Set ModelTarget to its address and ModelTargetStable to true; the caller retains runner ownership. Empty attachment Mode forwards bytes; local-allow and policy select HTTP mediation. policy requires PolicyURL or PolicyFile. Call modelservice.Release to release an attachment made through this lower-level API.

For non-defaults - backend override, custom kernel, sized memory/CPUs, networking

  • set the matching Options fields before calling Run. The lifecycle API:
FunctionPurpose
workspace.CreateBuild and prepare a named workspace rootfs and manifest
workspace.RunBuild, run, collect result state, and optionally clean up
workspace.StartStart an existing named workspace from its manifest
workspace.ApplyApply declared restart/network changes and stopped-workspace agent egress policy changes while preserving unrelated manifest fields; live egress changes fail before any write
workspace.DeleteStop or kill a live workspace as requested, then delete its disk and state. Idempotent and explicit: an absent workspace returns success with Deleted false and no event, so retried teardown never fails but a caller can tell nothing was removed
workspace.DeleteOptionsSelect graceful stop or forced kill before deletion
workspace.DeleteResultThe shared lifecycle Response, plus Deleted distinguishing “removed” from “was already absent”
workspace.AbsentReport whether nothing of the workspace exists (no records, no root directory); a partially created workspace is present
workspace.InspectAsk the backend supervisor for current runtime state
workspace.StatusRead enriched local workspace status from state files
workspace.VolumeDiskUsageMeasure a named volume’s backing image: provisioned, filesystem-used, and host-allocated MiB (vmkit.DiskUsage; nil when unreadable)
vmkit.DiskAssessmentOverprovisioned / vmkit.DiskAssessmentNearlyFullThe advisory DiskUsage.Assessment verdict values
vmkit.DiskUsageThe three sizes of a disk image — provisioned capacity, filesystem-used, and sparse host allocation — carried as RootfsUsage on inspect/status responses, with an advisory Assessment (overprovisioned / nearly-full)
workspace.ResizeGrow or shrink a stopped workspace’s rootfs disk in place (ResizeOptions.Progress reports typed check, disk, filesystem, verification, and publication phases; refuses while running or while snapshots exist; returns ResizeResult with the new vmkit.DiskUsage)
workspace.WaitBlock until the workspace reaches a terminal state (WaitOptions bounds it; returns a WaitResult, or WaitTimeoutError on timeout)
workspace.ResultStatusRead status plus guest result output
workspace.ArtifactsForRead declared ingress and egress artifacts
workspace.GetArtifact / workspace.GetArtifactWithOptionsCopy a declared output artifact from a stopped workspace; the options form reports typed phase and byte progress
workspace.Copy / workspace.CopyWithOptionsCopy files between the host and a stopped workspace disk; the options form reports typed phase and byte progress
workspace.GuestRootfsLayerTarExport a stopped workspace’s filesystem as an OCI layer tar via a guest maintenance boot (backends without host ext4 tooling)
workspace.Clone / workspace.CloneWithOptionsClone a stopped/prepared workspace; the options form reports typed copy progress against the source workspace’s logical byte total
workspace.ReadLogsRead a workspace serial log
workspace.ReadSupervisorLogsRead a workspace’s host-side supervisor companion logs
workspace.ReadEventsRead the concurrency-safe, bounded lifecycle event history; malformed persistence returns an error
workspace.ReadEgressAuditRead the egress mediator’s recorded allow/deny/MITM/DNS/UDP decisions (EgressEvent, from EgressAuditPath)
workspace.ReadBrokerAccessRead the egress broker’s per-request decision records (EgressEvent, from BrokerAccessPath)
workspace.MergeEgressEventsMerge the mediator and broker streams into one time-ordered view
workspace.SampleStatsSample CPU, memory, and I/O for a running workspace
workspace.NetworkRead configured and runtime network state
workspace.ListList named workspaces from local state
workspace.ControlRun a lifecycle control action (halt, quarantine, pause, resume, stop, kill, delete, gc). quarantine uses the complete ordered containment primitive and returns its typed phases and capture tag in vmkit.Response.Containment; use workspace.Quarantine when the incident receipt is also needed
workspace.RequestShutdownAsk guest PID 1 to begin graceful shutdown through the structured exec control channel; lifecycle callers normally use Control("halt") instead
workspace.QuarantineAtomically mark containment, freeze vCPUs, sever host authority, capture evidence while frozen, and stop into custody. Takes workspace.QuarantineOptions and returns the typed result of every phase. Capture failure never resumes execution or authority
workspace.QuarantineOptionsSkipCapture freezes and severs but omits the snapshot before final custody (accepting loss of volatile evidence); CaptureTag overrides the generated tag
workspace.QuarantineResultResponse, typed Containment phases, evidence capture fields, and an IncidentReceipt summarizing host-observed lifecycle, egress, broker, and secret-access records for the quarantined session
workspace.ReadContainmentRead the durable phase result. Marker presence remains an execution fence even when this document is missing or malformed
vmkit.ContainmentResultDurable typed result with freeze, severance, capture, stop, and custody phases, plus the accepted time, backend, captureRequired, capture tag, and overall state
vmkit.ContainmentPhaseStatus / vmkit.ContainmentPhaseResultPhase state and observation; statuses are vmkit.ContainmentPhasePending, vmkit.ContainmentPhaseCompleted, vmkit.ContainmentPhaseSkipped, and vmkit.ContainmentPhaseFailed
vmkit.ValidateContainmentResultReject malformed phase status, missing observation times, out-of-order completion, or final custody without a completed stop
vmkit.ContainmentMarkerDirName / vmkit.ContainmentResultName / vmkit.ContainmentMarkerDir / vmkit.ContainmentResultPathStable containment persistence names and paths for integrations that inspect host-owned workspace state
vmkit.ContainmentMarkedFail-closed marker-presence check; any filesystem error other than a confirmed missing marker is treated as contained
workspace.IncidentReceiptSelf-contained, session-scoped incident summary. It reports destinations, byte counts, and secret names and outcomes without storing content or secret values; Complete and Errors make audit-read failures explicit
workspace.BrokerAuditSummaryBroker request totals, destination verdicts, byte counts, and the names of swapped secret references
workspace.SecretAuditSummarySecret-access totals grouped by secret name and outcome; values are never present
workspace.ForensicCaptureTagPrefixTag prefix (forensic-) for automatic quarantine captures, so they are identifiable on sight and never collide with operator tags
workspace.Pause / workspace.ResumeFreeze and thaw a running workspace’s vCPUs in place
workspace.SnapshotCapture a tagged memory-plus-disk snapshot of a running or paused workspace. Ordinary snapshot dispatch is denied after containment is marked; quarantine owns its frozen-capture exception
workspace.SnapshotForensicCapture for investigation rather than restore: the guest secret purge is skipped, because credential material is the evidence and lives only in volatile memory. The manifest records forensic and frozenProcessState; secrets remain materialized and NOT purged, which the restore path refuses, so the capture cannot be rehydrated as a workspace
workspace.CreateFromSnapshotFork a new workspace from another workspace’s snapshot and resume it
workspace.SnapshotList / workspace.SnapshotRemoveList or delete a workspace’s snapshots (host-side). Removal refuses the capture named by an active containment custody record
vmkit.SafeSnapshotTagReport whether a snapshot tag is a bounded, path-safe identifier
workspace.SuperviseRun the optional restart-policy loop for a workspace
workspace.GCReconcile running workspace records as one bounded batch; returns GCResult with reaped targets and per-target GCFailure values instead of stopping at the first failure
workspace.ReadManifest / workspace.WriteManifestManage workspace manifests directly

workspace.Control(ctx, opts, command) takes the action as its positional command argument — one of halt, quarantine, pause, resume, stop, kill, delete, or gc — and rejects anything else. The CLI’s stop is a registry-level alias of halt: typing microagent stop runs the identical graceful-shutdown mechanism and records the identical halted outcome on a clean exit. Calling workspace.Control(ctx, opts, "stop") directly, though, is a distinct library command — same shutdown mechanism as halt, but it records the terminal state stopped, not halted. Both clean commands make a two-second, best-effort structured exec request for the guest to run sync before dispatching shutdown. The attempt and outcome are written to lifecycle event history. A failed or timed-out flush never lets the guest block the halt; the control operation proceeds. kill and quarantine do not make this preparation request. Raw quarantine dispatch is refused so every library adapter uses the ordered primitive. The terminal event also carries vmkit.LifecycleAudit. It combines the provenance-labeled Options.Caller, Options.Purpose, host-declared manifest commands, notification ownership, and a bounded best-effort guest process snapshot. Guest processes are explicitly guestReported; kill skips that request. Quarantine freezes first and preserves process state in the forensic memory capture rather than asking the guest for a process list. It links a successful capture through the audit record’s evidence reference.

Type or functionPurpose
vmkit.CallerAttributionAdapter channel plus optional caller-supplied subject and delegated authority, with explicit assurance
vmkit.DeclaredWorkOne host-recorded manifest command and its role
vmkit.GuestProcessOne bounded, guest-reported process observation
vmkit.WorkInFlightDeclared work, guest observations, capture status, and evidence reference
vmkit.NotificationRecordRecords that notification was not performed and remains caller-owned
vmkit.ValidateLifecycleAuditValidates provenance vocabulary and bounds before supervisor dispatch
workspace.LifecycleInspectTimeoutMaximum delay allowed for the guest process snapshot

For a running workspace, both graceful commands then call workspace.RequestShutdown before dispatching host lifecycle control. Guest PID 1 sends the persisted OCI stop signal to the workload process group and powers off; a rejection or timeout fails closed without escalating to a hard VMM signal. delete also removes the local state directory after the supervisor confirms; gc sweeps workspaces whose start-time lifetime lease expired. workspace.Pause and workspace.Resume are thin wrappers over the pause and resume actions and share their capability gate.

workspace.Copy(ctx, stateDir, debugfsPath, source, target) and workspace.GetArtifact(ctx, stateDir, debugfsPath, name, artifactName, target) operate on a stopped workspace’s disk. On hosts with ext4 tooling they shell out to debugfs from e2fsprogs: pass the binary path in debugfsPath. There is no in-library default — pass "debugfs" to resolve via PATH (the CLI’s own default is a PATH lookup with a /opt/homebrew/opt/e2fsprogs/sbin/debugfs fallback for macOS Homebrew); an empty string fails.

CopyWithOptions, GetArtifactWithOptions, and CloneWithOptions accept an operation.ProgressFunc. The original functions are shorthand with no callback. Progress messages describe operations rather than caller paths, and completed transfers report trustworthy byte totals.

pkg/workspace boots VMs through companion binaries that ship with the CLI: microagent-firecracker-supervisor and microagent-guestinit on Linux, microagent-applevf-supervisor on macOS. The library resolves them relative to an install base: first the running executable’s own directory (and its ../libexec), then the directory of microagent found on PATH. The second base is what makes resolution work for embedders: your program’s os.Executable() is not microagent’s install prefix. Without a microagent install on PATH (or explicit overrides) the lookup falls back to bare names like microagent-firecracker-supervisor, which fail unless those are themselves on PATH. The same two-base resolution covers the packaged kernel (../libexec/kernels/<backend>/<arch>/Image).

Deploying an embedder to a host without the microagent CLI therefore means shipping the companions yourself. Either place them next to your binary, set Options.SupervisorPath / Options.GuestInitPath / Options.KernelPath, or set the MICROAGENT_FIRECRACKER_SUPERVISOR / MICROAGENT_APPLEVF_SUPERVISOR environment variables (checked before the install-base search). Installers that need to mirror packaged resolution can use workspace.FirecrackerSupervisorPathFromExecutable (and the AppleVFSupervisorPathFromExecutable / GuestInitPathFromExecutable equivalents) to derive a companion path from a bin/microagent executable. workspace.Supervisor(opts) returns the resolved vmkit.Supervisor for the selected backend if you want to verify resolution up front.

Application operations return operation.Error for stable categories: validation, state conflict, not found, resource exhaustion, unsupported behavior, policy denial, and transient failure. Use errors.As or operation.IsKind; do not classify an operation by matching its message:

result, err := workspace.Start(ctx, opts)
if operation.IsKind(err, operation.ErrorConflict) {
// inspect current workspace state before retrying
}

The error unwraps its cause, so ordinary errors.Is and errors.As checks continue to work. CLI and MCP render the same category independently of the message wording.

workspace.WorkspaceNotFoundError is the structured “no such workspace” error. It is returned by the console helpers, workspace.Exec (and the other structured-exec entry points), workspace.SampleStats, and workspace.Status when a workspace has no runtime or event state. It supports errors.Is, so classify missing workspaces separately from stopped, halted, or quarantined ones:

if _, err := workspace.Status(opts); errors.Is(err, workspace.WorkspaceNotFoundError{}) {
// never created, or already deleted
}

Options is a plain value: every lifecycle function takes its own copy, so sharing a template Options across goroutines and customizing per call is safe. Structured exec is safe to run concurrently against one running workspace. Each Exec/ExecStream call dials its own connection and the guest service handles each connection in its own goroutine, running each command as an independent guest process. Lifecycle mutations are a different story — Run, Start, Control, Snapshot, Copy, and the other lifecycle functions read and write shared per-workspace state files. The package makes no documented guarantee about concurrent mutations of the same workspace name. Treat the lifecycle of a given workspace as single-threaded (operations on different workspace names are independent) unless you have verified a specific interleaving yourself.

workspace.SendConsoleCommand returns workspace.ConsoleReadTimeoutError when --send-style command completion is not observed before the send timeout; the error carries any partial output captured before the deadline. If the console connection closes before the completion marker arrives, SendConsoleCommand returns workspace.ConsoleCompletionUnknownError with any partial output captured before EOF. workspace.ProbeShellCommand uses the same marker protocol with a no-op command to verify a shell target can complete a command round trip. Callers that need explicit readiness semantics can use workspace.ShellReadinessSignalWithMode with workspace.ShellReadinessProbeTCP for TCP accept reachability or the command probe mode for end-to-end command readiness. workspace.WaitConsoleCommandReady waits for that command readiness without opening a second interactive session for the caller. Use workspace.DialConsole when the caller needs the returned connection. A terminal client can call workspace.ResizeConsole with that connection and the current rows and columns. The returned supported value is false for an older guest that did not negotiate resize support.

Structured exec uses workspace.Exec(ctx, opts, request) with pkg/workspace/exec/protocol.ExecRequest — callers import the protocol package for the request and result types. Build a request with protocol.NewExecRequest(argv) (which sets the protocol version and single-response mode) and set what you need:

  • Argv — the command as an argument vector; no shell is implied.
  • Env, Cwd, Stdin — environment, working directory, and stdin bytes (stdin is capped at protocol.DefaultOutputLimitBytes).
  • TimeoutMS — per-command guest-side timeout; the service default is protocol.DefaultTimeout (5 minutes).
  • OutputLimitBytesStdout / OutputLimitBytesStderr — per-stream capture caps, each at most protocol.DefaultOutputLimitBytes (10 MiB). Output beyond a cap is dropped and the result’s StdoutTruncated / StderrTruncated flag is set.

A nil Go error means the host reached the guest exec service and decoded a structured result — it says nothing about the command’s outcome. Check ExecResult.Status (protocol.ExecStatus) first:

StatusMeaning
exitedthe process ran to completion; ExitCode is set
signaledthe process was killed by a signal
timed_outthe per-command timeout elapsed and the process was terminated
failed_to_startthe command never started (bad path, invalid request)

ExecResult.ExitCode is a *int (JSON tag exit_code) and is nil unless Status is exited — dereferencing it unconditionally panics exactly when a command times out or fails to start. Guard it:

result, err := workspace.Exec(ctx, opts, req)
if err != nil { /* transport / workspace-state error */ }
switch {
case result.Status == protocol.ExecStatusExited && *result.ExitCode == 0:
// success
case result.Status == protocol.ExecStatusExited:
// nonzero guest exit — not a Go error
default:
// timed_out, signaled, or failed_to_start: ExitCode is nil
}

Nonzero guest exit codes are not Go errors. Use workspace.ExecWithMetadata when callers need retry accounting via workspace.ExecRetryMetadata. Transient transport failures are retried by the shared exec layer before the final result or workspace.ExecRetryExhaustedError is returned. workspace.IsRetryableExecTransient exposes the same classifier for callers that need to reason about exec transport errors directly. The execReady readiness signal in the runtime contract (vmkit.RuntimeReadiness.ExecReady, produced by workspace.ExecReadinessSignal) uses the same protocol with a no-op command to verify the service end-to-end. Exec gates on it for up to workspace.ExecReadyWait after start so an immediate post-start command does not surface a transient failure.

workspace.ExecStream(ctx, opts, request, onChunk) runs the same request in streaming mode: the guest emits stdout/stderr chunk frames as the command runs (delivered to onChunk) followed by a terminal result frame. In stream mode the returned ExecResult carries status, exit code, timing, and truncation flags but not the output bytes - those arrive as chunks. The CLI exposes this as microagent exec --stream.

Set workspace.Options.Progress to receive typed connect, retry, execute, and first-output boundaries. The first-output event is emitted before its chunk is delivered, so a presentation adapter can stop before writing stream data.

workspace.MarkActivity(opts) stamps a per-workspace activity marker file (mtime = last genuine use) and is called on each real exec/connect. The deadman watcher and gc sweep read it to measure idleness, so a declared --ttl lease is renewed by activity and only an idle VM is reaped. Internal readiness probes do not call it, so background liveness traffic cannot keep an abandoned VM alive.

The egress broker is a host-side forward proxy served on a vsock listener. The guest sends a reference and the broker injects the credential into the upstream request. Response-side guarantees depend on the endpoint’s explicit assurance. Declare it per workspace with Options.Broker (*vmkit.BrokerConfig) or Options.Brokers (multiple endpoints — setting both is rejected). vmkit.BrokerConfig carries the terminate-mode Upstream, the host-side Secret reference, and guest wiring (GuestListen, BaseURLEnv, Proxy). It also carries the Capture opt-in, optional UpstreamCAFile, Assurance, optional semantic Grant, and proxy ConnectAllowlist. Request fills transport defaults such as the vsock port and guest listen address. BrokerCredentialDisclosure names the response disclosure mode; BrokerCredentialDisclosureDenyExact is the required semantic value.

Rather than constructing the struct by hand, use the shared parsers — they fail closed on partial declarations and pasted literal secrets, so every surface (CLI, Agentfile, MCP, your program) builds an identical broker:

cfg, err := workspace.ParseBrokerConfig(
"https://api.anthropic.com", // upstream
"ANTHROPIC_API_KEY=env:ANTHROPIC_API_KEY", // NAME=<scheme>:<ref>, held host-side
[]string{"ANTHROPIC_BASE_URL"}, // base-URL env keys pointed at the broker
false, // proxy: set HTTPS_PROXY/HTTP_PROXY in the guest
false, // capture: governed raw-capture opt-in
"", // ca: PEM bundle for a private upstream cert
workspace.BrokerSecurityOptions{
Assurance: "semantic", // finite typed operations
GrantPath: "./anthropic-grant.yaml", // YAML/JSON operation contract
},
)
if err != nil {
panic(err)
}
opts.Broker = cfg

workspace.ParseBrokerEndpoints(specs) parses the repeatable ;-separated key=value endpoint spec strings (the --broker-endpoint grammar) into Options.Brokers. For what the broker enforces and how it relates to EgressMode and MITM mediation, see semantic broker grants and egress mediation.

Mediation readiness uses vmkit.MediationReadinessSignal(ctx, mediation, state, observedAt, timeout) to apply the shared live reachability contract. It returns ready only when the workspace is running and the declared mediation target accepts a bounded TCP probe. Required mediation target failures include an error; optional mediation target failures are reported as not ready without a hard error.

Use pkg/kernel when your program wants microagent to manage backend kernel assets directly.

result, err := kernel.Install(ctx, kernel.InstallOptions{
Backend: vmkit.BackendLinuxKVM,
Architecture: "amd64",
})
if err != nil {
panic(err)
}
verified, err := kernel.Verify(kernel.VerifyOptions{
Path: result.Path,
SHA256: result.SHA256,
})
if err != nil {
panic(err)
}
_ = verified

kernel.DefaultSource() returns the production manifest source: the TUF trust root embedded in the binary plus the canonical metadata/targets URLs. Pass it (or your own ManifestSource) to kernel.FetchTargets and feed the targets to kernel.CheckUpdate to classify an installed kernel as current, optional (behind latest but at the security floor), security (missing security fixes), or unknown. kernel.Support(backend, arch) reports whether a kernel image is present at the resolved path for a backend/architecture pair without installing anything.

You normally don’t call Install for the boot path: workspace.EnsureKernel runs inside workspace.Create/Run/Start/CreateFromSnapshot and installs the default kernel into the managed per-user path when none is present. Importing pkg/kernel is what arms it - the package registers the installer at init via workspace.RegisterProgressKernelInstaller (a workspace.ProgressKernelInstaller func; the indirection exists because pkg/kernel depends on pkg/workspace). The callback receives the same typed kernel progress that an explicit kernel.InstallOptions.Progress callback would receive. The older RegisterKernelInstaller remains available for embedders that do not need progress. A program that imports only pkg/workspace performs no implicit downloads: a missing kernel surfaces at boot. Add a blank import of pkg/kernel (or ship a kernel yourself) to choose the behavior you want. An explicit Options.KernelPath is always used as-is.

Use pkg/imagecache when an orchestrator wants reusable rootfs baselines.

record, err := imagecache.Pull(ctx, imagecache.PullOptions{
StateDir: "/home/me/.microagent",
ImageRef: "docker.io/library/ubuntu@sha256:...",
Architecture: "amd64",
})
if err != nil {
panic(err)
}
_ = record

workspace.CanReuseRootfsBaseline(opts) is the predicate that decides whether a workspace can clone a pulled baseline instead of building. It is true when the requested size and setuid policy can use the standard baseline. Commands, env, declared files, disks, ports, shells, and hostnames travel on the per-boot config disk or kernel command line. They do not change rootfs bytes. Wire a resolver into Options.RootfsBaseline (typically imagecache.Find) and workspace.Create clones automatically when the predicate holds. The store seeds itself: Options.RootfsBaselineSave (wired by the CLI to imagecache.SaveBaseline) records the first plain build of an image as a baseline, so later creates and runs clone without an explicit image pull. perf.BootOptions carries the same pair, so a boot benchmark measures the clone path a repeat run takes instead of a rebuild that path skips. Baseline records carry the hash of the guest init they were built with (workspace.GuestInitSHA256) and the rootfs SHA-256. Publication removes the shared rootfs’s host write bits; reuse requires the init to match and validates that the baseline still has its recorded immutable posture. imagecache.ValidateImmutableRootfs(record) exposes that posture check to other library consumers. Derived rootfs.Provenance.RootfsBase, workspace manifests, and vmkit.Response.RootfsBase preserve that source identity without claiming the private workspace disk is immutable. workspace.CopyFile reflinks on filesystems that support it (btrfs/XFS/APFS), so a clone is metadata-only where possible; workspace.CopyFileReplace is the overwrite variant. workspace.BuildVerification uses the measured base SHA-256 as a fresh private clone’s initial identity after checking the clone’s type and size. It does not reread a multi-gigabyte disk before first boot; quiescent status verification still hashes the private disk normally. workspace.BaselineSatisfiesSize(prov, opts) is the companion check the clone path applies to the resolved baseline. Its recorded bytes must cover the workspace’s effective size (profile-implied sizes the predicate cannot see), or the clone falls through to a real build.

Nothing per-workspace is baked into a rootfs. Each boot, the lifecycle assembles a guest run config (workspace.GuestBootConfig → workspace.GuestRunConfig: command, mode, env, ports, mounts, forwards, console shell, maintenance flag). It writes the config with any declared files as a raw tar stream to the workspace’s config disk (workspace.WriteConfigDisk; path from workspace.ConfigDiskFile). The supervisor attaches that file read-only as the last block device (vmkit.Config.ConfigDiskPath; guest device path math in vmkit.VirtioBlockDevice) and names it on the kernel command line. Declared file contents are captured once at create into a durable archive (workspace.WriteFilesArchive, path from workspace.FilesArchivePath; modes parsed by rootfs.ParseFileMode) so later boots deliver the create-time bytes even if the sources change. Each regeneration re-records the disk’s hash in the manifest verification block via workspace.RefreshManifestVerificationConfig, so the command and files the guest runs never escape attestation.

After a successful create-time setup boot, the lifecycle records the modified rootfs and final boot config together with SetupComplete. Failed setup boots leave that checkpoint untouched, so a later start retries setup instead of trusting a partial result.

imagecache.PruneWithOptions accepts PruneOptions.Progress and reports one bounded current/total counter while reconciling the index. Prune is the source-compatible no-callback shorthand. The model store offers the same pair as model.PruneWithOptions and model.Prune.

Use pkg/diagnostics for host preflight checks.

resp, err := diagnostics.Check(ctx, diagnostics.Options{
Backend: vmkit.BackendLinuxKVM,
Arch: "amd64",
})
if err != nil {
// resp still carries structured support details when available, so
// inspect both. Surface the error rather than swallowing it.
log.Printf("diagnostics.Check: %v", err)
}
_ = resp

Set diagnostics.Options.Progress to receive typed probe boundaries. Fast checks may replace one another without presentation; a slow current probe can be shown without parsing diagnosis text.

The CLI contains presentation, flag parsing, build metadata output, and raw terminal handling. microVM orchestration and management capabilities are exposed through the Go packages, and the mapping below shows the equivalent library entry points.

If you already know the CLI, this is the lookup for the equivalent library call:

CLI commandLibrary call
microagent runworkspace.Run
microagent dispatchworkspace.RunDispatch
microagent initscaffold.Generate
microagent createworkspace.Create
microagent startworkspace.Start
microagent create --from-snapshotworkspace.CreateFromSnapshot
microagent start --from-snapshotworkspace.Start with Options.FromSnapshot
microagent statusworkspace.Status (local) / workspace.Inspect (live, via supervisor)
microagent wait / microagent start --waitworkspace.Wait
microagent resultworkspace.ResultStatus
microagent list / microagent ls / microagent psworkspace.List
microagent halt / microagent stop / microagent kill / microagent deleteworkspace.Control (one function; the action is the positional command argument: halt, quarantine, pause, resume, stop, kill, delete, or gc)
microagent gcworkspace.GC (bounded batch reconciliation with per-target failures)
microagent quarantineworkspace.Quarantine (mark, freeze, sever, frozen capture, stop, custody). workspace.Control(ctx, opts, "quarantine") uses the same primitive with capture skipped
microagent pause / microagent resumeworkspace.Pause / workspace.Resume
microagent snapshot create / list / deleteworkspace.Snapshot / workspace.SnapshotList / workspace.SnapshotRemove
microagent applyworkspace.Apply
microagent superviseworkspace.Supervise
microagent connectworkspace.DialConsole / ResizeConsole / SendConsoleCommand (raw terminal mode stays CLI-only)
microagent execworkspace.Exec
microagent logsworkspace.ReadLogs
microagent eventsworkspace.ReadEvents (text lifecycle view) / workspace.ReadTrajectory (structured joined view)
microagent egressworkspace.ReadEgressAudit + workspace.ReadBrokerAccess (merged via workspace.MergeEgressEvents)
microagent statsworkspace.SampleStats
microagent cpworkspace.Copy
microagent cloneworkspace.Clone
microagent commit / microagent image pushcommit.Commit / commit.Push (commit.Options.Progress spans local commit phases; push has its own progress callback)
microagent artifact / microagent artifact getworkspace.ArtifactsFor / workspace.GetArtifact
microagent networkworkspace.Network

workspace.NewSessionID creates an execution-lifetime identifier for callers that build raw requests. workspace.TrajectoryRecord is the common envelope returned by workspace.ReadTrajectory; its Raw field preserves the complete source record. The joined view includes constraint revisions from workspace.ReadConstraintHistory. Each revision carries an independently reconstructable manifest snapshot plus config-disk and verification hashes. workspace.ConstraintRevision is the complete record, and workspace.ConstraintHistoryPath returns its host-owned path. Retention uses workspace.DefaultMaxConstraintRevisions.

Status responses summarize the bounded history in Response.ConstraintHistory. The field uses vmkit.ConstraintHistoryStatus; its oldest and latest entries are vmkit.ConstraintRevisionRef values without embedded manifests.

workspace.Options.Purpose and CorrelationID are opaque caller context persisted in vmkit.Identity; the library records them verbatim and does not use them for policy decisions. For lifecycle mutations, set Options.Purpose to the operator’s reason before calling Control, Quarantine, or Delete; adapters expose that same value as reason. Set Options.Caller only from caller context your integration already holds. Use Assurance: "caller_asserted" when microagent has not authenticated the subject; leaving the caller unset produces a library-channel attribution with unavailable assurance rather than a fabricated principal. | microagent model | model.Pull / model.List / model.Remove / model.Prune / modelrunner.Ensure | | microagent volume | volume.CreateWithOptions / volume.ResizeWithOptions for progress-aware mutations; volume.Create / volume.Resize are no-callback shorthands; volume.List / volume.Get / volume.Remove / volume.Attach cover the remaining lifecycle | | microagent secret check | secret.DefaultRegistry / secret.Registry.Check | | microagent doctor / microagent host | diagnostics.Check | | microagent contract | vmkit.NewRuntimeContract | | microagent kernel install / microagent kernel verify | kernel.Install / kernel.Verify | | microagent rootfs build | rootfs.Builder.Build | | microagent image | imagecache.Pull / List / Tag / Remove / Prune | | microagent registry login / logout / list | registryauth.Login / registryauth.Logout / registryauth.List | | microagent perf / microagent perf boot / microagent perf ready / microagent perf footprint / microagent perf steady | perf.Boot / Ready / Footprint / Steady | | microagent profiles | workspace.ProfileNames / workspace.LookupProfile | | microagent serve mcp | CLI-only MCP stdio transport over the existing package APIs | | microagent model serve | modelrunner.Ensure (start or reuse a host-local model runner process) | | microagent version | CLI-only build metadata output | | microagent.yaml (spec parsing) | workspace.ReadSpec / ApplySpecFile |

The library calls take options structs and return typed responses. For reusable runtime behavior, prefer the package API. The remaining CLI-only commands are presentation concerns such as help, version, and raw terminal mode around an already-open console connection.