# Get an audit event Source: https://docs.microsandbox.dev/api-reference/endpoints/audit-events/get-an-audit-event /api-reference/openapi.json get /v1/events/{event_id} Retrieve one audit event by its identifier. # List audit events Source: https://docs.microsandbox.dev/api-reference/endpoints/audit-events/list-audit-events /api-reference/openapi.json get /v1/events List audit events for the organization with cursor pagination and optional filters. # Get a usage summary Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/get-a-usage-summary /api-reference/openapi.json get /v1/billing/usage Return billable usage for the organization. # Get an invoice Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/get-an-invoice /api-reference/openapi.json get /v1/billing/invoices/{invoice_id} # Get billing summary Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/get-billing-summary /api-reference/openapi.json get /v1/billing # Get per-sandbox usage Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/get-per-sandbox-usage /api-reference/openapi.json get /v1/billing/usage/sandbox Return billable usage grouped by sandbox for a selected UTC time range. # Get per-volume storage usage Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/get-per-volume-storage-usage /api-reference/openapi.json get /v1/billing/usage/storage Return persistent storage usage grouped by volume for a selected UTC time range. # List billing plans Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/list-billing-plans /api-reference/openapi.json get /v1/billing/plans # List invoices Source: https://docs.microsandbox.dev/api-reference/endpoints/billing/list-invoices /api-reference/openapi.json get /v1/billing/invoices # List organization members Source: https://docs.microsandbox.dev/api-reference/endpoints/members/list-organization-members /api-reference/openapi.json get /v1/members List organization members and their roles with cursor pagination. # Get the current organization Source: https://docs.microsandbox.dev/api-reference/endpoints/organization/get-the-current-organization /api-reference/openapi.json get /v1/me/org Returns the organization associated with the current credential. # Get quota usage Source: https://docs.microsandbox.dev/api-reference/endpoints/quotas/get-quota-usage /api-reference/openapi.json get /v1/quotas Return current resource usage, plan limits, and organization-specific quota overrides. # Create a sandbox Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/create-a-sandbox /api-reference/openapi.json post /v1/sandboxes Create a sandbox, optionally start it immediately, and optionally wait until it is ready. # Delete a sandbox Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/delete-a-sandbox /api-reference/openapi.json delete /v1/sandboxes/{sandbox_id} Delete a sandbox. Resource cleanup continues asynchronously. # Delete a sandbox by name Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/delete-a-sandbox-by-name /api-reference/openapi.json delete /v1/sandboxes/by-name/{name} Delete a sandbox selected by its organization-scoped name. Resource cleanup continues asynchronously. # Get a sandbox Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/get-a-sandbox /api-reference/openapi.json get /v1/sandboxes/{sandbox_id} Retrieve one sandbox by its unique identifier. # Get a sandbox by name Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/get-a-sandbox-by-name /api-reference/openapi.json get /v1/sandboxes/by-name/{name} Retrieve one sandbox by its organization-scoped name. # Get sandbox metrics Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/get-sandbox-metrics /api-reference/openapi.json get /v1/sandboxes/{sandbox_id}/metrics # List mounted volumes Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/list-mounted-volumes /api-reference/openapi.json get /v1/sandboxes/{sandbox_id}/volumes # List sandboxes Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/list-sandboxes /api-reference/openapi.json get /v1/sandboxes List the organization's sandboxes with cursor pagination and optional label filtering. # Start a sandbox Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/start-a-sandbox /api-reference/openapi.json post /v1/sandboxes/{sandbox_id}/start Start a sandbox and optionally wait until it is running. # Start a sandbox by name Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/start-a-sandbox-by-name /api-reference/openapi.json post /v1/sandboxes/by-name/{name}/start Start a sandbox selected by its organization-scoped name. # Stop a sandbox Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/stop-a-sandbox /api-reference/openapi.json post /v1/sandboxes/{sandbox_id}/stop Stop a running sandbox. # Stop a sandbox by name Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/stop-a-sandbox-by-name /api-reference/openapi.json post /v1/sandboxes/by-name/{name}/stop Stop a running sandbox selected by its organization-scoped name. # Update a sandbox Source: https://docs.microsandbox.dev/api-reference/endpoints/sandboxes/update-a-sandbox /api-reference/openapi.json patch /v1/sandboxes/{sandbox_id} Rename a sandbox by updating its display name or slug. # Create a snapshot Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/create-a-snapshot /api-reference/openapi.json post /v1/snapshots Create a managed or host-volume disk snapshot asynchronously. # Delete a snapshot Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/delete-a-snapshot /api-reference/openapi.json delete /v1/snapshots/{snapshot_id} Delete a managed disk snapshot by its immutable identifier. # Delete a snapshot by name Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/delete-a-snapshot-by-name /api-reference/openapi.json delete /v1/snapshots/by-name/{name} Delete a managed disk snapshot by its organization-unique name. # Get a snapshot Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/get-a-snapshot /api-reference/openapi.json get /v1/snapshots/{snapshot_id} Retrieve a managed disk snapshot by its immutable identifier. # Get a snapshot by name Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/get-a-snapshot-by-name /api-reference/openapi.json get /v1/snapshots/by-name/{name} Retrieve a managed disk snapshot by its organization-unique name. # Get a snapshot operation Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/get-a-snapshot-operation /api-reference/openapi.json get /v1/snapshot-operations/{operation_id} Poll an asynchronous snapshot operation. # List snapshot candidates Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/list-snapshot-candidates /api-reference/openapi.json get /v1/sandboxes/snapshot-candidates List persistent, stopped sandboxes supported by the current disk snapshot policy. # List snapshot operations Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/list-snapshot-operations /api-reference/openapi.json get /v1/snapshot-operations List asynchronous snapshot operations requested by this organization. # List snapshots Source: https://docs.microsandbox.dev/api-reference/endpoints/snapshots/list-snapshots /api-reference/openapi.json get /v1/snapshots List the organization's managed disk snapshots. # Check if a file exists Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/check-if-a-file-exists /api-reference/openapi.json get /v1/volumes/{id}/files/exists # Copy a file or directory Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/copy-a-file-or-directory /api-reference/openapi.json post /v1/volumes/{id}/files/copy # Create a directory Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/create-a-directory /api-reference/openapi.json post /v1/volumes/{id}/files/mkdir # Create a volume Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/create-a-volume /api-reference/openapi.json post /v1/volumes Create a named persistent volume with optional capacity and labels. # Delete a file or directory Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/delete-a-file-or-directory /api-reference/openapi.json delete /v1/volumes/{id}/files # Delete a volume Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/delete-a-volume /api-reference/openapi.json delete /v1/volumes/{id} Schedule an unused named volume for deletion. # Get file details Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/get-file-details /api-reference/openapi.json get /v1/volumes/{id}/files/stat # Get the default volume Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/get-the-default-volume /api-reference/openapi.json get /v1/volumes/default # Get volume metrics Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/get-volume-metrics /api-reference/openapi.json get /v1/volumes/{id}/metrics # List directory contents Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/list-directory-contents /api-reference/openapi.json get /v1/volumes/{id}/files # List volumes Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/list-volumes /api-reference/openapi.json get /v1/volumes List persistent volumes available to the organization, including current usage. # Move a file or directory Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/move-a-file-or-directory /api-reference/openapi.json post /v1/volumes/{id}/files/rename # Read a file Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/read-a-file /api-reference/openapi.json get /v1/volumes/{id}/files/content # Update a volume Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/update-a-volume /api-reference/openapi.json patch /v1/volumes/{id} Update a named volume's capacity limit or labels. # Write a file Source: https://docs.microsandbox.dev/api-reference/endpoints/volumes/write-a-file /api-reference/openapi.json put /v1/volumes/{id}/files/content # Overview Source: https://docs.microsandbox.dev/api-reference/overview Authenticate cloud REST API requests with API keys or personal tokens, and handle errors and pagination. microsandbox cloud is in [private beta](/cloud/overview); the API is available to organizations with access. The microsandbox cloud REST API manages sandboxes and the accounts around them. Use it directly when an SDK does not cover your workflow, or when you need account, billing, or audit endpoints. For running code in sandboxes (exec, streaming, PTY, file transfer, SSH), use the [SDKs](/sdk/overview) or [CLI](/cli/overview). They speak the sandbox command channel, which is not part of this REST surface. ## Credentials The sidebar separates endpoints by who the request represents: | Credential | Format | Represents | Use for | | - | - | - | - | | API key | `msb_...` | An organization | Services, SDKs, CLI automation, and organization resources | | Personal token | `msb_pat_...` | A user | Account and organization administration | API keys and personal tokens are both sent as bearer tokens: ```bash theme={null} curl https://api.microsandbox.dev/v1/sandboxes \ -H "Authorization: Bearer $MSB_API_KEY" ``` API keys are created in the [dashboard](https://dashboard.microsandbox.dev/access/api-keys). API-key paths infer the organization from the key. Personal-token paths include the organization slug when the request needs an organization. ## Base URL ```text theme={null} https://api.microsandbox.dev ``` ## Errors Errors return an `error` object with a stable machine-readable `code`, a human-readable `message`, and optional structured `details`: ```json theme={null} { "error": { "code": "invalid_api_key", "message": "unauthorized", "details": null } } ``` ## Pagination List endpoints use cursor pagination. Pass `limit` to size the page and `cursor` to continue from a previous response: ```json theme={null} { "data": [ ... ], "has_more": true, "next_cursor": "eyJv..." } ``` Request the next page with `?cursor=`; `has_more: false` means you have everything. ## Usage and billing The usage endpoints report metered consumption for the current period. Reported cost figures are estimates; the [dashboard](https://dashboard.microsandbox.dev/billing) is the source of truth for billing. # Delete your account Source: https://docs.microsandbox.dev/api-reference/personal/account/delete-your-account /api-reference/openapi.personal.json delete /v1/users/me Deletes the account's personal information, signs out active sessions, removes organization memberships, and revokes pending invitations sent by the user. Audit history is retained. Requires fresh credential proof: the current password (password-backed accounts) or a TOTP code (MFA-enabled accounts). At least one must be supplied; both being valid is fine but a single matching proof is enough. Returns `409 Conflict` if the user is the sole owner of an organization - ownership must be transferred first. # Get your profile Source: https://docs.microsandbox.dev/api-reference/personal/account/get-your-profile /api-reference/openapi.personal.json get /v1/users/me # Update your profile Source: https://docs.microsandbox.dev/api-reference/personal/account/update-your-profile /api-reference/openapi.personal.json patch /v1/users/me # Get an audit event Source: https://docs.microsandbox.dev/api-reference/personal/audit-events/get-an-audit-event /api-reference/openapi.personal.json get /v1/orgs/{slug}/events/{event_id} # List audit events Source: https://docs.microsandbox.dev/api-reference/personal/audit-events/list-audit-events /api-reference/openapi.personal.json get /v1/orgs/{slug}/events Returns customer-visible audit events with optional filters. # Cancel the subscription Source: https://docs.microsandbox.dev/api-reference/personal/billing/cancel-the-subscription /api-reference/openapi.personal.json post /v1/orgs/{slug}/billing/cancel Cancellation takes effect at the end of the billing period. # Change the billing plan Source: https://docs.microsandbox.dev/api-reference/personal/billing/change-the-billing-plan /api-reference/openapi.personal.json put /v1/orgs/{slug}/billing/plan # Get an invoice Source: https://docs.microsandbox.dev/api-reference/personal/billing/get-an-invoice /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/invoices/{invoice_id} # Get billing summary Source: https://docs.microsandbox.dev/api-reference/personal/billing/get-billing-summary /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing # Get estimated usage costs Source: https://docs.microsandbox.dev/api-reference/personal/billing/get-estimated-usage-costs /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/usage Includes the subscription and estimated overage for the current period. # Get sandbox usage Source: https://docs.microsandbox.dev/api-reference/personal/billing/get-sandbox-usage /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/usage/sandbox Groups compute usage by sandbox and day for the requested time range. # Get storage usage Source: https://docs.microsandbox.dev/api-reference/personal/billing/get-storage-usage /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/usage/storage Groups persistent storage usage by volume and day for the requested time range. # List billing plans Source: https://docs.microsandbox.dev/api-reference/personal/billing/list-billing-plans /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/plans # List invoices Source: https://docs.microsandbox.dev/api-reference/personal/billing/list-invoices /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/invoices # Open the payment portal Source: https://docs.microsandbox.dev/api-reference/personal/billing/open-the-payment-portal /api-reference/openapi.personal.json get /v1/orgs/{slug}/billing/payment-portal Returns a URL for managing payment methods. # List API keys Source: https://docs.microsandbox.dev/api-reference/personal/credentials/list-api-keys /api-reference/openapi.personal.json get /v1/orgs/{slug}/api-keys Admins and owners see all keys. Members see only their own keys. # List personal tokens Source: https://docs.microsandbox.dev/api-reference/personal/credentials/list-personal-tokens /api-reference/openapi.personal.json get /v1/users/me/pats Returns metadata without token values. # Revoke a personal token Source: https://docs.microsandbox.dev/api-reference/personal/credentials/revoke-a-personal-token /api-reference/openapi.personal.json delete /v1/users/me/pats/{id} Returns not found when the token is missing or already revoked. # Accept an invite Source: https://docs.microsandbox.dev/api-reference/personal/invites/accept-an-invite /api-reference/openapi.personal.json post /v1/invites/{token}/accept # Cancel an invite Source: https://docs.microsandbox.dev/api-reference/personal/invites/cancel-an-invite /api-reference/openapi.personal.json delete /v1/orgs/{slug}/invites/{invite_id} # Decline an invite Source: https://docs.microsandbox.dev/api-reference/personal/invites/decline-an-invite /api-reference/openapi.personal.json post /v1/invites/{token}/decline # Invite a member Source: https://docs.microsandbox.dev/api-reference/personal/invites/invite-a-member /api-reference/openapi.personal.json post /v1/orgs/{slug}/invites # List pending invites Source: https://docs.microsandbox.dev/api-reference/personal/invites/list-pending-invites /api-reference/openapi.personal.json get /v1/orgs/{slug}/invites # Change a member's role Source: https://docs.microsandbox.dev/api-reference/personal/members/change-a-members-role /api-reference/openapi.personal.json patch /v1/orgs/{slug}/members/{user_id} # List organization members Source: https://docs.microsandbox.dev/api-reference/personal/members/list-organization-members /api-reference/openapi.personal.json get /v1/orgs/{slug}/members # Remove a member Source: https://docs.microsandbox.dev/api-reference/personal/members/remove-a-member /api-reference/openapi.personal.json delete /v1/orgs/{slug}/members/{user_id} # Configure organization SSO Source: https://docs.microsandbox.dev/api-reference/personal/oidc/configure-organization-sso /api-reference/openapi.personal.json put /v1/orgs/{slug}/oidc # Get organization SSO settings Source: https://docs.microsandbox.dev/api-reference/personal/oidc/get-organization-sso-settings /api-reference/openapi.personal.json get /v1/orgs/{slug}/oidc # Remove organization SSO settings Source: https://docs.microsandbox.dev/api-reference/personal/oidc/remove-organization-sso-settings /api-reference/openapi.personal.json delete /v1/orgs/{slug}/oidc # Create an organization Source: https://docs.microsandbox.dev/api-reference/personal/organization/create-an-organization /api-reference/openapi.personal.json post /v1/orgs The current user becomes its owner. # Delete an organization Source: https://docs.microsandbox.dev/api-reference/personal/organization/delete-an-organization /api-reference/openapi.personal.json delete /v1/orgs/{slug} Hides the organization immediately and schedules its resources for cleanup. The request must confirm the organization slug. # Get an organization Source: https://docs.microsandbox.dev/api-reference/personal/organization/get-an-organization /api-reference/openapi.personal.json get /v1/orgs/{slug} # List your organizations Source: https://docs.microsandbox.dev/api-reference/personal/organization/list-your-organizations /api-reference/openapi.personal.json get /v1/orgs # Update an organization Source: https://docs.microsandbox.dev/api-reference/personal/organization/update-an-organization /api-reference/openapi.personal.json patch /v1/orgs/{slug} # Get quota usage Source: https://docs.microsandbox.dev/api-reference/personal/quotas/get-quota-usage /api-reference/openapi.personal.json get /v1/orgs/{slug}/quotas # Create or update a registry credential Source: https://docs.microsandbox.dev/api-reference/personal/registry-credentials/create-or-update-a-registry-credential /api-reference/openapi.personal.json put /v1/orgs/{slug}/registries Each registry host can have one stored credential. # Delete a registry credential Source: https://docs.microsandbox.dev/api-reference/personal/registry-credentials/delete-a-registry-credential /api-reference/openapi.personal.json delete /v1/orgs/{slug}/registries/{id} # List registry credentials Source: https://docs.microsandbox.dev/api-reference/personal/registry-credentials/list-registry-credentials /api-reference/openapi.personal.json get /v1/orgs/{slug}/registries Returns credential metadata without secret values. # Check sandbox name availability Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/check-sandbox-name-availability /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandbox-slug/check Check whether the sandbox slug is valid and available. # Create a sandbox Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/create-a-sandbox /api-reference/openapi.personal.json post /v1/orgs/{slug}/sandboxes By default, the sandbox is created without starting. Use `start=true` to start it immediately and `wait_for=running` to wait until it is ready. # Delete a sandbox Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/delete-a-sandbox /api-reference/openapi.personal.json delete /v1/orgs/{slug}/sandboxes/{sandbox_id} Resource cleanup continues asynchronously. # Get a sandbox Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/get-a-sandbox /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandboxes/{sandbox_id} # Get sandbox metrics Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/get-sandbox-metrics /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandboxes/{sandbox_id}/metrics Returns CPU, memory, disk, and network metrics for a time range. # List mounted volumes Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/list-mounted-volumes /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandboxes/{sandbox_id}/volumes # List sandboxes Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/list-sandboxes /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandboxes # Start a sandbox Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/start-a-sandbox /api-reference/openapi.personal.json post /v1/orgs/{slug}/sandboxes/{sandbox_id}/start # Stop a sandbox Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/stop-a-sandbox /api-reference/openapi.personal.json post /v1/orgs/{slug}/sandboxes/{sandbox_id}/stop # Suggest a sandbox name Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/suggest-a-sandbox-name /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandbox-slug/suggest Generate an available sandbox slug. # Update a sandbox Source: https://docs.microsandbox.dev/api-reference/personal/sandboxes/update-a-sandbox /api-reference/openapi.personal.json patch /v1/orgs/{slug}/sandboxes/{sandbox_id} # Create a snapshot Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/create-a-snapshot /api-reference/openapi.personal.json post /v1/orgs/{slug}/snapshots # Delete a snapshot by ID Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/delete-a-snapshot-by-id /api-reference/openapi.personal.json delete /v1/orgs/{slug}/snapshots/{snapshot_id} # Delete a snapshot by name Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/delete-a-snapshot-by-name /api-reference/openapi.personal.json delete /v1/orgs/{slug}/snapshots/by-name/{name} # Get a snapshot by ID Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/get-a-snapshot-by-id /api-reference/openapi.personal.json get /v1/orgs/{slug}/snapshots/{snapshot_id} # Get a snapshot by name Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/get-a-snapshot-by-name /api-reference/openapi.personal.json get /v1/orgs/{slug}/snapshots/by-name/{name} # Get a snapshot operation Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/get-a-snapshot-operation /api-reference/openapi.personal.json get /v1/orgs/{slug}/snapshot-operations/{operation_id} # List sandboxes available for snapshots Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/list-sandboxes-available-for-snapshots /api-reference/openapi.personal.json get /v1/orgs/{slug}/sandboxes/snapshot-candidates # List snapshot operations Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/list-snapshot-operations /api-reference/openapi.personal.json get /v1/orgs/{slug}/snapshot-operations # List snapshots Source: https://docs.microsandbox.dev/api-reference/personal/snapshots/list-snapshots /api-reference/openapi.personal.json get /v1/orgs/{slug}/snapshots # Check if a file exists Source: https://docs.microsandbox.dev/api-reference/personal/volumes/check-if-a-file-exists /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes/{id}/files/exists # Check if files exist Source: https://docs.microsandbox.dev/api-reference/personal/volumes/check-if-files-exist /api-reference/openapi.personal.json post /v1/orgs/{slug}/volumes/{id}/files/exists # Copy a file or directory Source: https://docs.microsandbox.dev/api-reference/personal/volumes/copy-a-file-or-directory /api-reference/openapi.personal.json post /v1/orgs/{slug}/volumes/{id}/files/copy # Create a directory Source: https://docs.microsandbox.dev/api-reference/personal/volumes/create-a-directory /api-reference/openapi.personal.json post /v1/orgs/{slug}/volumes/{id}/files/mkdir # Create a volume Source: https://docs.microsandbox.dev/api-reference/personal/volumes/create-a-volume /api-reference/openapi.personal.json post /v1/orgs/{slug}/volumes # Delete a file or directory Source: https://docs.microsandbox.dev/api-reference/personal/volumes/delete-a-file-or-directory /api-reference/openapi.personal.json delete /v1/orgs/{slug}/volumes/{id}/files # Delete a volume Source: https://docs.microsandbox.dev/api-reference/personal/volumes/delete-a-volume /api-reference/openapi.personal.json delete /v1/orgs/{slug}/volumes/{id} # Get file details Source: https://docs.microsandbox.dev/api-reference/personal/volumes/get-file-details /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes/{id}/files/stat # Get the default volume Source: https://docs.microsandbox.dev/api-reference/personal/volumes/get-the-default-volume /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes/default # Get volume metrics Source: https://docs.microsandbox.dev/api-reference/personal/volumes/get-volume-metrics /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes/{id}/metrics # List directory contents Source: https://docs.microsandbox.dev/api-reference/personal/volumes/list-directory-contents /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes/{id}/files # List volumes Source: https://docs.microsandbox.dev/api-reference/personal/volumes/list-volumes /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes # Move a file or directory Source: https://docs.microsandbox.dev/api-reference/personal/volumes/move-a-file-or-directory /api-reference/openapi.personal.json post /v1/orgs/{slug}/volumes/{id}/files/rename # Read a file Source: https://docs.microsandbox.dev/api-reference/personal/volumes/read-a-file /api-reference/openapi.personal.json get /v1/orgs/{slug}/volumes/{id}/files/content # Update a volume Source: https://docs.microsandbox.dev/api-reference/personal/volumes/update-a-volume /api-reference/openapi.personal.json patch /v1/orgs/{slug}/volumes/{id} # Write a file Source: https://docs.microsandbox.dev/api-reference/personal/volumes/write-a-file /api-reference/openapi.personal.json put /v1/orgs/{slug}/volumes/{id}/files/content # Week of April 3, 2026 Source: https://docs.microsandbox.dev/changelog/2026-04-03 The microsandbox rewrite around an embeddable SDK, smoltcp networking, and a composable filesystem. **Released this week:** [v0.3.3](https://github.com/superradcompany/microsandbox/releases/tag/v0.3.3) through [v0.3.10](https://github.com/superradcompany/microsandbox/releases/tag/v0.3.10) ## New features **Microsandbox rewrite** Rewritten around an embeddable SDK, smoltcp-based networking, and a composable filesystem: * First-class Rust SDK that the CLI is built on. * User-space network stack (smoltcp) with an in-sandbox DNS resolver and TLS proxy. * Composable filesystem layering OCI images, host volumes, and writable overlays through one VFS. * Redesigned policy and config model shared across CLI, SDK, and `Sandboxfile`. Breaking change. **Other features** * **Per-command exec flags for `msb run`.** Pass `--env`, `--workdir`, `--tty`, `--timeout`, etc. directly without a `Sandboxfile`. ## Bug fixes * VM logs split into `guest.log` and `host.log` instead of interleaving. * Reopening inodes via `/.vol` on macOS no longer fails under `O_RESOLVE_BENEATH`. * Overlay `readdir` resolves real inode numbers instead of surfacing `0`. * `ExecTimeout` is returned consistently when an exec call hits its timeout. * Sandbox creation validates `workdir` up front and defaults `cwd` to `/` when unset. * `msb self update` resolves the latest version before downloading the bundle. # Week of April 10, 2026 Source: https://docs.microsandbox.dev/changelog/2026-04-10 File-level volume mounts, TypeScript SDK streams, and `msb shell` removal. **Released this week:** [v0.3.11](https://github.com/superradcompany/microsandbox/releases/tag/v0.3.11) · [v0.3.12](https://github.com/superradcompany/microsandbox/releases/tag/v0.3.12) ## New features * **File-level volume mounts.** Mounts now target individual files, not just directories. See [Sandbox volumes](/sandboxes/volumes). * **`fs.readStream` in the TypeScript SDK.** Async-iterable file reads instead of buffering whole files in memory. * **`sandbox.metricsStream()` in the TypeScript SDK.** Async iterable of CPU, memory, and I/O samples, mirroring the Rust SDK. * **`msb shell` removed.** Use `msb exec --tty -- bash` instead. ## Bug fixes * The network proxy now recomputes `Content-Length` after substituting secrets into request bodies. * `msb run` execution options (env, cwd, signal handling) only apply when `--tty` is set. * Extended attributes on symlinks and `listxattr` initialization now match the underlying VFS. # Week of April 17, 2026 Source: https://docs.microsandbox.dev/changelog/2026-04-17 New Python SDK, Docker image publishing, and TLS proxy fixes. **Released this week:** [v0.3.13](https://github.com/superradcompany/microsandbox/releases/tag/v0.3.13) ## New features **Python SDK** PyO3 bindings exposing the same sandbox, exec, networking, and filesystem APIs as the Rust and TypeScript SDKs. ```python theme={null} async with await Sandbox.create("my-sandbox", image="alpine") as sb: out = await sb.shell("echo hello") print(out.stdout_text) ``` Install with `pip install microsandbox`. See the [Python SDK reference](/sdk/python/sandbox). **Other features** * **Docker image publishing.** Releases now publish a `microsandbox` Docker image alongside the binary artifacts. * **Interactive `msb self uninstall`** with a multi-select prompt over CLI, SDK shims, cached images, and state directory. * **Interactive `msb exec`.** Running without a command opens a picker over registered scripts and recent exec history. * **Upstream CA trust config.** Point the TLS proxy at a custom upstream CA bundle; the old `--tls-ca` flag names are deprecated but still resolve. * **`--allow-private-ips`** opts permissive policies into RFC1918 ranges without disabling policy entirely. ## Bug fixes * Concurrent TLS connections through the in-sandbox MITM proxy no longer interleave plaintext between sessions. * TLS 1.3 connections no longer drop bytes that arrived in the same TCP segment as the final handshake message. * Sandboxes that boot faster than host clock convergence no longer reject internal TLS traffic with `CERT_NOT_YET_VALID`. # Week of April 24, 2026 Source: https://docs.microsandbox.dev/changelog/2026-04-24 Block-backed OCI rootfs, guest rlimits, and TypeScript SDK improvements. **Released this week:** [v0.3.14](https://github.com/superradcompany/microsandbox/releases/tag/v0.3.14) ## New features **Block-backed OCI rootfs** Image rootfs now ships as a packed VMDK with EROFS metadata and copy-on-write overlays instead of an extracted directory, cutting boot time and host disk usage. See the [images overview](/images/overview). **Other features** * **Sandbox-wide guest rlimits.** Apply default `RLIMIT_*` values to every process inside the guest. * **`execStreamWithConfig` in the TypeScript SDK.** Stream stdout/stderr while passing the same per-exec options as `execWithConfig`. * **Run microsandbox via cargo, npx, and pipx.** `cargo install microsandbox`, `npx microsandbox`, and `pipx run microsandbox` all bring up a working CLI. ## Bug fixes * The SDK now self-heals when the bundled `msb` binary is missing, re-downloading it on demand. # Week of May 1, 2026 Source: https://docs.microsandbox.dev/changelog/2026-05-01 TypeScript SDK redesign, network policy redesign, disk-image volumes, and more. **Released this week:** [v0.4.0](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.0) · [v0.4.1](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.1) · [v0.4.2](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.2) · [v0.4.3](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.3) ## New features **Redesigned TypeScript SDK** Builder API matching the Rust SDK, with `await using`, typed errors, async iterables, and bundled native binaries (no postinstall download). ```ts theme={null} await using sandbox = await Sandbox.builder("my-sandbox") .image("alpine:latest") .cpus(2) .create(); ``` See the [TypeScript SDK reference](/sdk/typescript/sandbox). **Redesigned network policy** `--network-policy` is gone. Rules now carry their own direction, action, target, protocol, and ports through a single grammar: `[:]@[:[:]]`. ```bash theme={null} msb run alpine --name agent \ --net-default-egress deny \ --net-rule "allow@public,allow@host" \ --net-rule "deny@private:tcp:445" ``` See the [networking overview](/networking/overview). **Other features** * **Disk-image volume mounts.** Attach qcow2, raw, or vmdk images as virtio-blk devices at any guest path; `readonly` is now consistent across volume types. See [Sandbox volumes](/sandboxes/volumes). * **Inline `--script` flag.** Register scripts on the command line with `--script NAME=BODY`; the file form is now `--script-path NAME:PATH`. See the [CLI reference](/cli/sandbox-commands). * **`msb` alias.** Installs from npm, pip, and cargo now put both `microsandbox` and `msb` on PATH. * **`host.microsandbox.internal`.** Sandboxes can reach the host through this well-known DNS name. * **Trust host CAs (opt-in).** Sandboxes can trust the host's CA bundle for internal TLS endpoints. See [Networking TLS](/networking/tls). * **DNS interception over TCP/53 and DoT/853.** Closes gaps where apps bypassed policy by switching transports. See [Networking DNS](/networking/dns). * **Custom TLS certs and insecure registries** for self-hosted image registries. See the [images overview](/images/overview). * **Per-sandbox `libkrunfw` override** for SDK callers developing against unreleased firmware. * **Installer rejects unsupported glibc** up front, instead of producing confusing runtime errors. ## Bug fixes * Domain and `suffix=` rules now enforce consistently across DNS, SNI, and policy layers. * The Node/TypeScript SDK supports the same secret injection options as the Rust SDK. * macOS reads system nameservers via `SCDynamicStore`, matching what the OS actually uses. * The npm platform package ships `libkrunfw` under its canonical name, fixing load failures on some Linux distros. # Week of May 15, 2026 Source: https://docs.microsandbox.dev/changelog/2026-05-15 Go SDK, file-first disk snapshots, guest init handoff, exec and boot logs, and DNS egress policy. **Released this week:** [v0.4.4](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.4) · [v0.4.5](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.5) · [v0.4.6](https://github.com/superradcompany/microsandbox/releases/tag/v0.4.6) ## New features **Go SDK** A first-class Go SDK with full parity to the Rust, TypeScript, and Python SDKs: sandbox lifecycle, exec and PTY, filesystem, networking, secrets, snapshots, volumes, images, and event streams. The library uses CGO over a runtime-loaded FFI bundle, so `go get` works without a Rust toolchain. ```go theme={null} ctx := context.Background() sb, err := microsandbox.CreateSandbox(ctx, "my-sandbox", microsandbox.WithImage("alpine:latest"), microsandbox.WithCPUs(2), ) if err != nil { log.Fatal(err) } defer sb.Close() ``` See the [Go SDK reference](/sdk/go/sandbox). **File-first disk snapshots** Stopped sandboxes can be snapshotted to a content-addressed directory and used to boot fresh sandboxes on any compatible host. Snapshots stay sparse via reflink and `SEEK_DATA`/`SEEK_HOLE` copying, so create and inspect stay fast. The CLI ships `msb snapshot create | open | list | list-dir | remove | reindex | export | import | verify`, and `msb run --from-snapshot ` boots a fork. The same surface is available in all four SDKs. ```bash theme={null} msb snapshot create baseline --from-sandbox my-sandbox msb run --from-snapshot baseline --name fork ``` See [Sandbox snapshots](/sandboxes/snapshots). **Guest init handoff** `--init` hands PID 1 inside the guest off to systemd, OpenRC, s6, or any other init binary while the agent continues serving the host channel from a child process. Shutdown adapts to the new PID 1 (for example, `SIGRTMIN+4` for systemd) with a `SIGTERM` fallback. All three SDKs gained matching `init` / `initWith` surfaces. ```bash theme={null} msb run debian:12 \ --init /lib/systemd/systemd \ --init-arg --unit=multi-user.target \ --init-env container=microsandbox ``` See the [systemd services example](/how-to/guest/systemd-services). **Exec logs and structured boot errors** Each sandbox now writes a per-session `exec.log` (JSON Lines) capturing stdout, stderr, and PTY output, readable via the new `msb logs` command and `logs()` SDK methods. Sandboxes that fail before the agent is ready now emit a structured `boot-error.json` that the CLI renders as a typed error block instead of a generic "process exited" message. Spawn-time exec failures are now reported through a typed `ExecFailed` message with kinds such as `NotFound`, `PermissionDenied`, `NotExecutable`, and `OutOfMemory`. The CLI exits 127, 126, or 1 per POSIX convention. See [Sandbox logs](/sandboxes/logs). **DNS queries are subject to egress policy** DNS lookups are now treated as a regular egress action rather than an exception. Under a deny-by-default policy with no rules, DNS is blocked; `allow DomainSuffix(".good.com")` only permits lookups for `*.good.com`; `allow host udp/53 + tcp/53` grants resolution wholesale. The `public_only` and `non_local` presets prepend a DNS-allow rule so default sandboxes still resolve names, and `Rule.allowDns()` / `Rule.allow_dns()` is available across SDKs. See [Networking DNS](/networking/dns). **Other features** * **Ingress policy gate on published ports.** Inbound TCP connections on published ports are now evaluated against the network policy before the listener accepts them; denied peers receive a TCP RST instead of a graceful close. See the [networking overview](/networking/overview). * **`MSB_HOME` env override.** Point a sandbox at an isolated state directory without touching `$HOME`, useful for CI jobs that share a runner. The build script honors the same variable, so build-time and runtime paths agree. * **Secret injection for Basic auth.** Placeholders inside `Authorization: Basic ` headers are now decoded, substituted, and re-encoded. The proxy also detects bypass attempts via URL percent-encoding, JSON unicode escapes, and placeholders split across TCP writes. The Python SDK gained the same `SecretInjection` options (`headers`, `basic_auth`, `query_params`, `body`) as the Node SDK. * **`createWithPullProgress` in the Node TS SDK.** Stream image pull events (layer downloads, extraction) while creating a sandbox; the returned `PullProgressCreate` resolves to the live sandbox. See the [TypeScript SDK reference](/sdk/typescript/sandbox). * **`--replace-grace` flag.** Configure how long `replace()` waits for the previous sandbox to shut down before escalating, exposed in the CLI and all SDKs. ## Bug fixes * `replace()` no longer hangs for 30 seconds when the previous sandbox is mid-shutdown; it now escalates from `SIGTERM` to `SIGKILL` after the grace period. * Stdin payloads larger than the kernel pipe buffer (about 64 KiB on Linux) are delivered correctly, and broken-pipe errors surface as a new `stdin_error` exec event instead of being silently dropped. * Address families are gated on host route availability, so v4-only hosts no longer advertise an IPv6 address into the guest and v6-only hosts can publish ports. * Connection timeouts during the relay handshake now respect the 30-second deadline and prefer `boot-error.json` over a raw IO error when available. * Prebuilt runtime downloads use the platform certificate store, so builds behind enterprise TLS proxies with custom CAs succeed instead of failing with `UnknownIssuer`. * OCI digests with path traversal components are rejected, keeping cache filenames safe. * The Node SDK accepts kebab-case `link-local` in plain-object network policies, matching the documented public form. * The Node SDK's `msb` path resolution works under Bun, which does not propagate JS-side `process.env` mutations to native code. * Bind-mounting host directories the caller does not own (for example `/tmp`, `/var`, mounted USB drives) no longer fails with `Operation not permitted` before the VM boots. # Week of May 22, 2026 Source: https://docs.microsandbox.dev/changelog/2026-05-22 Rotation-aware log streaming, raw agent client across SDKs, per-mount passthroughfs policies, network policy CLI cleanup, configurable port bind addresses, and ergonomic --script. ## New features **Rotation-aware log streaming** `Sandbox.log_stream` / `logStream` / `LogStream` lands in the Rust, Node, Python, and Go SDKs, alongside `read_logs` for sorted snapshots. The engine merges `exec.log`, `runtime.log`, and `kernel.log` including their rotated siblings, and each entry carries an opaque `cursor` so consumers can resume after a disconnect. `msb logs` and `msb logs -f` now ride the same engine; if a follower falls behind retention it receives a typed `MissedRotation` error with a hint to restart instead of silently skipping records. ```python theme={null} async for entry in sandbox.log_stream(follow=True): print(entry.timestamp, entry.source, entry.data) ``` See [Sandbox logs](/sandboxes/logs). **Raw agent client in every SDK** A new `AgentClient` surface lets SDK callers talk to a sandbox's `agentd` directly through the relay, sending and receiving framed CBOR without going through the typed sandbox API. Rust ships both a typed tier (with a validated `core.ready` handshake and cached ready bytes) and a raw tier; Node, Python, and Go expose the raw tier and keep CBOR encoding in userland. Useful for experimenting with new agent operations or building higher-level tooling on top of the protocol. ```ts theme={null} const client = await AgentClient.connectSandbox("dev"); const ready = client.ready(); const response = await client.request(frame); ``` See the [TypeScript SDK reference](/sdk/typescript/sandbox). **Per-mount passthroughfs policies** Two explicit knobs replace the previous boolean flags on every mount. `stat_virtualization` chooses between `Strict`, `Relaxed`, and `Off`, and `host_permissions` chooses between `Private` and `Mirror`. Defaults stay `Strict + Private`, so existing sandboxes are unchanged. The new combinations make it possible to bind-mount foreign-owned read-only paths like `/tmp`, mirror guest `chmod` bits to the host inode, and create real host-visible symlinks from inside the guest. The `--mount` flag gains `tag:host[:ro][,stat-virt=...][,host-perms=...]` for opting in. See [Sandbox filesystem](/sandboxes/filesystem). **Network policy CLI consolidation** The egress and ingress flags collapse into one consistent surface. `--net-default ` sets both directions at once, `*.foo.com` is now accepted as a suffix shorthand inside `--net-rule` targets, and `--no-net` is sugar for `--net-default deny` (it now also blocks ingress, matching its name). TLD-broad patterns like `*.com` are rejected at parse time so they cannot widen blast radius by accident. `--deny-domain` and `--deny-domain-suffix` are removed; express the same intent with `--net-rule "deny@..."` plus `--net-default allow`. ```bash theme={null} msb run alpine \ --net-default deny \ --net-rule "allow@*.good.com,allow@host" ``` See the [networking overview](/networking/overview). **Configurable port bind addresses** Published ports can now bind to a specific host address rather than the implicit loopback. The CLI accepts `BIND_ADDR:HOST:GUEST` and `/udp` variants, and the Rust, Python, TypeScript, and Go SDKs gained matching bind-aware port APIs. Existing `HOST:GUEST` mappings continue to bind to `127.0.0.1`. ```bash theme={null} msb run nginx --port 0.0.0.0:8080:80 --port 127.0.0.1:9000:9000/udp ``` See the [networking overview](/networking/overview). **Ergonomic `--script` flag** `msb create --script NAME=BODY` now produces a runnable script: the body is wrapped with a shebang derived from `--shell` (default `/bin/sh`), and the escapes `\n`, `\t`, `\r`, `\\`, `\"`, `\'` are decoded so multiline scripts survive normal shell quoting. A new `--script-raw NAME=BODY` writes the body byte-for-byte for callers that bring their own shebang. `--shell` rejects empty, whitespace, and NUL values at parse time so a stray newline cannot inject lines into every generated script. ```bash theme={null} msb create --replace alpine --name py \ --script start='echo hello\npython3 -c "print(123)"' msb exec py -- start ``` See the [CLI reference](/cli/sandbox-commands). **Other features** * **Passthrough secret violation action.** A new `Passthrough` violation policy forwards requests containing secret placeholders without substituting the real value, scoped to a configurable list of host patterns. Useful for letting non-sensitive traffic flow to hosts that happen to share placeholder syntax. See [Sandbox secrets](/sandboxes/secrets). * **Python exec keyword arguments.** `sandbox.exec("python3", ["script.py"], cwd="/app", env={...}, timeout=30.0)` now works directly, instead of requiring an `ExecOptions` dict. See the [Python SDK reference](/sdk/python/execution). * **Configurable guest IP pools.** Deployments can override the default IPv4 and IPv6 guest pools, and the default IPv4 pool changes from `100.96.0.0/11` to `172.16.0.0/12` to avoid colliding with Tailscale. * **`msb start` accepts variadic sandbox names.** Start more than one sandbox in a single command. * **Agent relay supports up to 128 concurrent clients.** Raised from 16. The relay also reports its correlation-ID range size to each SDK during the handshake, so later changes will not silently misroute frames on older clients. * **Configurable shared-memory metrics registry.** Live per-sandbox metrics now live in a POSIX shared-memory segment instead of SQLite, removing steady-state writes to the catalog database. Capacity is tunable via `metrics.capacity` in `~/.microsandbox/config.json`; the public metrics API is unchanged. See [Sandbox metrics](/sandboxes/metrics). ## Bug fixes * TLS interception no longer fails on long-lived sandboxes; cached per-domain leaf certificates are now refreshed before they expire. * Sandbox writes are flushed to disk on `msb stop` and `sandbox.stop()`; previously the host could tear down the VM before the guest synced ext4, occasionally losing in-flight writes across stop and start. As part of this fix, `replace_with_grace` is renamed to `replace_with_timeout` across the CLI, Rust, Python, Node, and Go SDKs, and `stop_with_timeout` / `connect_with_timeout` are now available on `SandboxHandle`. * The microsandbox CA is now installed into guest trust directories with mode `0755`, creating those directories first when they are missing, so distro trust-store refreshes pick it up. * `msb logs --follow --json` emits JSON Lines for the follow records, not just the initial snapshot, so streaming consumers no longer hit a parse error mid-stream. * Request bodies that arrive already content-encoded (gzip, brotli, deflate) are preserved verbatim during secret substitution instead of being silently rewritten. * `msb run ./path` and other dot-prefixed inputs are now recognized as local image inputs instead of being interpreted as registry references. * Sandboxes with large environment-variable payloads no longer overflow at startup. * `AllSandboxMetrics` in the Go SDK reports the real uptime instead of zero. * Several `--net-rule` suffix entry points now reject TLD-broad patterns like `*.com` at parse time, with a clear `SuffixTooBroad` error. # Week of May 29, 2026 Source: https://docs.microsandbox.dev/changelog/2026-05-29 Native SSH and SFTP, configurable OCI root disk size, msb copy and rootfs patch flags, hardened mount options, env-backed secret shorthand, and a fix for multi-second published-port stalls. **Released this week:** [v0.5.0](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.0) · [v0.5.1](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.1) · [v0.5.2](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.2) ## New features **Native SSH and SFTP** Sandboxes gain a first-class SSH surface across the CLI and every SDK without running `sshd` inside the guest. `msb ssh ` opens an interactive session, `msb ssh -- ` runs a one-shot command, and `msb ssh serve` exposes an external SSH transport that standard `ssh` and `sftp` clients can connect to after `msb ssh authorize` registers a key. The SDK SSH namespace in Rust, TypeScript, Python, and Go supports interactive attach, exec, and SFTP, plus an in-process server mode. ```bash theme={null} msb ssh authorize --file ~/.ssh/id_ed25519.pub msb ssh serve devbox --host 127.0.0.1 --port 2222 ssh -p 2222 root@127.0.0.1 sftp -P 2222 root@127.0.0.1 ``` See the [SSH overview](/sandboxes/ssh). **Configurable OCI root disk size** The writable root disk for OCI sandboxes is now configurable, so workloads that generate large amounts of state during a session no longer have to fit inside the previous fixed default. `msb run --root-disk 8G ...` sets it from the CLI, and `sandbox_defaults.oci.root_disk` sets the deployment-wide default. The Rust, TypeScript, Python, and Go SDKs expose matching root-disk settings. Fresh managed OCI roots default to 4096 MiB; snapshot upper layers are copied as-is. ```python theme={null} from microsandbox import Image, RootDisk, Sandbox sandbox = await Sandbox.create( "worker", image=Image.oci("python:3.12", root_disk=RootDisk.managed(8192)), ) ``` See the [sandbox commands reference](/cli/sandbox-commands). **`msb copy` and rootfs patch flags** A new `msb copy` (alias `msb cp`) moves files host-to-sandbox, sandbox-to-host, within a single sandbox, or across two sandboxes, including recursive directories and symlinks. `msb run` and `msb create` accept `--copy`, `--copy-file`, `--copy-dir`, `--mkdir`, and `--rm` so a fresh sandbox can be prepared without a separate setup step. Guest paths are validated before the sandbox is created so typos fail fast. ```bash theme={null} msb run alpine \ --copy ./config.toml:/etc/app/config.toml \ --copy-dir ./certs:/etc/app/certs \ --mkdir /var/cache/app \ --rm /etc/motd msb copy ./local.txt devbox:/tmp/local.txt msb copy devbox:/tmp/a otherbox:/tmp/a ``` See the [CLI overview](/cli/overview). **Docker-style mount options with enforced `ro` and `noexec`** Volume mounts now use the Docker-style `source:guest:options` shape everywhere and accept `ro`, `rw`, `nosuid`, `noexec`, and `fstype=...` (for disk-image volumes). The host-side passthroughfs enforces read-only mounts so the guest cannot remount them writable, and the runtime drops mount-admin capability before user execs so user commands cannot undo `ro` or `noexec`. Direct SDK configs are validated before create or start so unsafe guest paths and policy combinations fail early. ```bash theme={null} msb run --name tools -v ./tools:/tools:ro,noexec alpine -- ls /tools ``` See the [volumes guide](/sandboxes/volumes). **Env-backed secret shorthand** `msb --secret` accepts a new `ENV@HOST` form that reads the value from the same-named host environment variable, so common API keys no longer need to be inlined in command arguments. The existing `ENV=VALUE@HOST` form is preserved for explicit values and renames. Missing, empty, or non-UTF-8 sources produce a clear error. ```bash theme={null} msb create python --name agent \ --secret "OPENAI_API_KEY@api.openai.com" ``` See the [secrets guide](/sandboxes/secrets). **Other features** * **Sandbox name byte limit.** Sandbox names are now validated as 1 to 128 UTF-8 bytes everywhere (CLI, all SDKs, metrics), with a typed error rather than a silent truncation. Names longer than 128 bytes are now rejected. See [Sandbox lifecycle](/sandboxes/lifecycle). * **Host UDP published ports.** Published-port mappings now support UDP end to end, with bounded peer allocation and a VM round-trip test. See the [networking overview](/networking/overview). * **Typed Python network destinations.** The Python SDK now accepts `Ip`, `Cidr`, `Domain`, `DomainSuffix`, `Group`, and `Any` destinations on `Rule`, alongside the legacy string form. See the [Python networking reference](/sdk/python/networking). * **Guest clock sync.** The runtime now sends a `core.clock.sync` frame on startup, every 60 seconds, and after the host wall clock jumps by more than 6 seconds. Sandboxes that survive a host sleep or suspend resume with the correct wall time instead of drifting until restart. ## Bug fixes * Published-port traffic from the host no longer stalls for several seconds before the guest receives the connection; the host listener now wakes the smoltcp poll loop immediately after accepting. * DNS-over-UDP responses are now delivered back to the guest as real Ethernet frames, so guest resolvers no longer occasionally time out even when the upstream query succeeded. * TLS-intercepted uploads no longer hang or end with EOF on large request bodies; the upstream stream is flushed after each forwarded plaintext batch. * TLS secret substitution is now tied to the original guest destination, DNS-cache binding, SNI, HTTP/1 `Host`, and observed HTTP/2 `:authority`, so spoofed or fronted hosts cannot trick the proxy into injecting real secret values. HTTP/2 HEADERS are decoded and re-encoded with bounded HPACK state, and HTTP/1 chunked and fixed-length bodies are rewritten safely. * Body-continuation chunks on long-lived TLS connections no longer corrupt binary uploads with `U+FFFD`, leak header-only secrets into request bodies, or skip substitution on pipelined follow-up requests. * SNI matching now enforces `deny` rules even when the guest connects to a literal IP with no DNS-cache binding, closing a path that previously let denied domains through over direct-IP HTTPS. * Bind mounts of host-owned directories are now mapped to the guest's resolved default user, so non-root guests can read and write project files mounted from the host. Other host owners surface as `65534:65534`. * Sandboxes with very long names now boot reliably; the agent relay socket is placed under a fixed-length runtime path and validated against `SUN_LEN` before spawn, with the legacy socket path retained as a fallback. * Network policies in the Python and Go SDKs treat bare IPv4 and IPv6 literals as host CIDR matches instead of trying to resolve them as domains. * `Sandbox.exec(cmd, options_dict)` and `exec_stream(cmd, options_dict)` in the Python SDK now actually apply `args` and other options, and `shell_with(..., timeout=...)` honors the same timeout path as `exec_with()`. `create_with_progress()` is callable synchronously again. * Sandboxes started under microsandbox 0.4 keep working for exec and shell after upgrading to 0.5; filesystem and SFTP operations against a pre-0.5 live sandbox now fail with a clear restart hint instead of a protocol-level error, and legacy OCI config rows are migrated to the new shape on first contact. * Split irqchip is re-enabled for x86 Linux VMs, restoring the previous interrupt routing path now that the underlying libkrun fix has shipped. * Released binaries now ship with the SSH feature enabled, so the new `msb ssh` commands work without rebuilding from source. # Week of June 5, 2026 Source: https://docs.microsandbox.dev/changelog/2026-06-05 OTLP sandbox metrics, SSH TCP forwarding, image archive commands, pruning, Python image management, Homebrew install, and smoother host upgrades. **Released this week:** [v0.5.3](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.3) · [v0.5.4](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.4) · [v0.5.5](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.5) ## New features **OTLP sandbox metrics with labels** The new `msb-metrics` binary exports live per-sandbox CPU, memory, disk, and network gauges over OTLP to backends like Grafana Cloud, Prometheus, Datadog, Alloy, and the OpenTelemetry Collector. Sandboxes can also carry labels: set them with `--label` on the CLI or through SDK builders, filter operations with the same flag, and OCI image labels flow into OTLP attributes automatically. Use `--exclude-label-key` for high-cardinality keys or `--no-labels` to export without them. ```bash theme={null} msb run python --name worker --label team=ml msb ls --label team=ml msb-metrics otel --endpoint https://otlp.example.com/v1/metrics ``` See the [`msb-metrics` overview](/observability/msb-metrics). **SSH TCP forwarding** The built-in SSH server now supports local (`-L`) and dynamic (`-D`) TCP forwarding. Forwarded connections open from inside the sandbox, so network policy applies normally and `127.0.0.1` means the sandbox loopback. Reverse (`-R`) and stream-local forwarding remain unsupported. ```bash theme={null} msb ssh serve devbox --host 127.0.0.1 --port 2222 ssh -p 2222 -L 8080:127.0.0.1:80 root@127.0.0.1 ssh -p 2222 -D 1080 root@127.0.0.1 ``` See the [SSH overview](/sandboxes/ssh). **Image archive load and save** `msb image load` (alias `msb load`) imports Docker or OCI archives into the local cache, and `msb image save` (alias `msb save`) exports cached images without a registry. Both commands work over stdin or files (`--input` / `--output`); save defaults to Docker format and accepts `--format oci` for OCI Image Layout. ```bash theme={null} docker save alpine:3.20 | msb image load msb image save alpine:3.20 --output alpine.tar msb image save alpine:3.20 --format oci --output alpine-oci.tar ``` See the [image commands reference](/cli/image-commands). **Image prune** `msb image prune` deletes cached image data that no sandbox or indexed snapshot uses, then reports the reclaimed bytes. Rust, TypeScript, and Go gain `Image.prune()` / `Image.Prune(ctx)`, replacing `Image.gc()` and `Image.gcLayers()`. ```bash theme={null} msb image prune --yes --format json ``` See the [images overview](/images/overview). **Python image management API** The Python SDK gains the same image cache surface as the other SDKs: `Image.get`, `Image.list`, `Image.inspect`, `Image.remove`, `Image.gc_layers`, and `Image.gc`, plus typed `ImageHandle`, `ImageDetail`, `ImageConfigDetail`, and `ImageLayerDetail`. Rootfs helpers remain on `Image`, and in-use removals raise `ImageInUseError`. ```python theme={null} from microsandbox import Image images = await Image.list() detail = await Image.inspect("python:3.12") await Image.remove("old:tag") ``` See the [Python SDK reference](/sdk/python/sandbox). **Homebrew install on macOS** microsandbox is now installable from the Homebrew tap, with formula updates published automatically for each release. ```bash theme={null} brew install superradcompany/tap/microsandbox ``` See the [quickstart](/getting-started/quickstart). **Agent protocol versioning** Newer hosts can keep working with older live sandboxes by negotiating an agent protocol version at connect time. Unsupported calls fail individually with typed `UnsupportedOperation` errors, replacing `Pre05SandboxRestartRequired` across the Rust, Python, TypeScript, and Go SDKs. **Other features** * **Grouped `msb` help output.** Top-level `msb --help` now groups commands into Sandboxes, Images, Storage, Installation, and other sections so the surface is easier to scan. Subcommand help is unchanged. * **Unified detached creation across SDKs.** Detached sandboxes now use the normal create path (`SandboxBuilder::detached(true)`, or `WithDetached()` in Go), replacing the separate Rust and TypeScript helpers. This is a breaking SDK source change; the CLI is unaffected. * **Attached sandboxes stop on creator exit.** Attached sandboxes now shut down when their creator process dies unexpectedly instead of lingering until the host handle is reaped. * **`--security restricted` profile.** The default profile restores guest-root behavior for workloads like Docker-in-Docker, while `--security restricted` keeps the previous `no_new_privs` and `CAP_SYS_ADMIN` drop. `msb inspect`, volume options, and tmpfs flags now show `ro`/`rw` plus `noexec`, `nosuid`, or `nodev` when set. ## Bug fixes * Non-loopback published-port throughput is no longer throttled to roughly 30 to 120 KB/s. * DNS queries denied by sandbox network policy now return `NXDOMAIN` instead of an empty answer. * The default exec profile no longer applies `no_new_privs` and the `CAP_SYS_ADMIN` drop, so `sudo` and Docker-in-Docker work again on the default profile. Use `--security restricted` to opt back into the previous hardening. * Sandbox builders now reject zero CPU and zero memory configurations at build time with a typed error. * Read-only consumers like `msb-metrics` no longer create an empty, schema-less `msb.db` when they start before the main daemon. * Human-facing CLI timestamps (`msb ls`, `msb ps`, image and snapshot listings) now render in the local system timezone. JSON output continues to emit RFC 3339 timestamps with an explicit UTC offset for machine consumers. * Sandboxes persisted by microsandbox 0.5.2 with the legacy `readonly` mount field now start on 0.5.3 and later. * Idle-timeout restarts no longer race against stale heartbeat files from the previous boot, and idle-timeout shutdowns now give the guest a chance to flush state. * Sandboxes with large environment-variable payloads now boot reliably with the released `msb_krun` 0.1.14. * `agentd` now sets `HOME` from the guest passwd entry for implicit root execs, so images like `ubuntu:24.04` get `/root` instead of inheriting `HOME=/`. Explicit users, sandbox or image users, and explicit `HOME` env values still take precedence. * `msb-metrics` preserves OTLP HTTP endpoint paths exactly, exports buffered gauge collections without LastValue aggregation loss, and ships in release builds alongside `msb`. # Week of June 12, 2026 Source: https://docs.microsandbox.dev/changelog/2026-06-12 Guest runtime metrics, idempotent named volumes, unified sandbox lifecycle APIs, explicit mount kind flags, cleaner installer, raw agent socket paths, and richer secret violation logs. **Released this week:** [v0.5.6](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.6) ## New features **Guest runtime metrics** `msb-metrics` and the per-sandbox metrics surface now report CPU, memory, disk, and network samples from the VMM instead of host process totals, so readings reflect what the guest actually used. Stopped sandboxes are excluded from exports, and the new fields flow through the CLI, the Rust, TypeScript, Python, and Go SDKs, and the MCP tool. ```bash theme={null} msb-metrics otel --endpoint https://otlp.example.com/v1/metrics msb ls --format json ``` See the [`msb-metrics` overview](/observability/msb-metrics). **Idempotent named volume mounts** Named volumes can now be mounted in one step: the CLI creates the backing volume if it does not exist, so a fresh sandbox can persist state without a separate `msb volume create`. The Rust, TypeScript, Python, and Go SDKs gain explicit `existing-only`, `create-only`, and `ensure-exists` modes on named mounts. ```bash theme={null} msb run --name worker --mount-named cache:/var/cache python ``` See the [volumes guide](/sandboxes/volumes). **Unified sandbox lifecycle APIs** `stop` and `kill` now wait for the sandbox to reach the requested state across the Rust, TypeScript, Python, and Go SDKs. Timeout-aware variants and a new `wait_until_stopped` / `waitUntilStopped` / `WaitUntilStopped` helper let you observe sandbox-domain stopped state. Request-only behavior is still available through explicit methods for fire-and-return callers. Scoped filesystem and SSH helpers are renamed to operation groups (`SandboxFsOps`, `SandboxSshOps`, and language-idiomatic variants), and SSH helper methods are now `open_client`, `prepare_server`, and `serve_connection`. This is a breaking SDK source change; the CLI is unaffected. ```python theme={null} result = await sandbox.stop(timeout=30) await sandbox.wait_until_stopped() ``` See the [Python SDK reference](/sdk/python/sandbox). **Explicit mount kind flags** New `--mount-dir`, `--mount-file`, `--mount-disk`, and `--mount-named` flags on `msb run` and `msb create` let you choose the mount kind directly instead of relying on `-v` source inference. Each flag uses the existing `SOURCE:DEST[:OPTIONS]` syntax with kind-specific option validation, and explicit directory and file sources are checked against the host path kind so typos fail early. ```bash theme={null} msb run alpine \ --mount-dir ./src:/app/src:ro \ --mount-file ./config.toml:/etc/app/config.toml \ --mount-named cache:/var/cache ``` See the [sandbox commands reference](/cli/sandbox-commands). **Other features** * **Raw agentd socket path.** `AgentClient::socket_path(name)` in Rust, `AgentClient.socketPath(name)` in TypeScript, `AgentClient.socket_path(name)` in Python, and `microsandbox.AgentSocketPath(name)` in Go return a sandbox's `agentd` relay socket path without connecting, so callers that splice raw bytes to the socket no longer have to open the framed client first. The C FFI gains `msb_agent_socket_path`. See the [Python agent client reference](/sdk/python/agent-client). * **Richer secret violation logs.** `block-and-log` and `block-and-terminate` actions now emit structured warnings and errors with the secret env var, placeholder, request context, match location, protocol, SNI, host, method, redacted path, and original guest destination. Body-continuation chunks on long-lived TLS connections carry the same context. `block` continues to be silent. See the [TLS networking guide](/networking/tls). * **Cleaner installer.** The CLI installer no longer edits shell startup files. It places runtime files under `$HOME/.microsandbox` (or `$MSB_HOME`), exposes `msb` and `microsandbox` through `~/.local/bin` symlinks, prints a PATH hint only when `~/.local/bin` is missing, and refreshes those links from `msb self update`. Existing non-symlink command paths are left alone instead of being overwritten. See the [quickstart](/getting-started/quickstart). * **Global log level for sandbox runs.** Global log flags now flow into the sandbox runtime when `msb run` or `msb create` does not pass `--log-level`, so `msb -v run ...` actually raises sandbox verbosity instead of being ignored. ## Bug fixes * Published-port responses no longer stall behind a slow host-side client; the relay now wakes the poll loop as soon as host-channel capacity frees up. * Long-running execs that take no host input, like builds, `sleep`, or batch commands, are no longer reclaimed by the idle-timeout monitor while still running. Heartbeat-based idle detection now tracks exec sessions, filesystem and TCP byte movement, and agentd heartbeats independently of serial or stream backpressure. * Stopped sandboxes no longer appear in metrics exports with a frozen value after a SIGKILL; the collector now skips slots whose updates have stopped instead of replaying the last sample indefinitely. # Week of June 19, 2026 Source: https://docs.microsandbox.dev/changelog/2026-06-19 Local and cloud backend routing in the SDKs, detached image init entrypoints, shared sandbox spec types, secret substitution through HTTP CONNECT tunnels and plain HTTP, and snapshot import hardening. **Released this week:** [v0.5.7](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.7) ## New features **Local and cloud backend routing in the SDKs** The Rust, TypeScript, Python, and Go SDKs can now target a local microsandbox install or a hosted cloud backend from the same program. A profile-aware config under `~/.microsandbox/config.json` plus `MSB_BACKEND`, `MSB_API_URL`, `MSB_API_KEY`, and `MSB_PROFILE` environment variables select the backend, and per-sandbox overrides let you mix local and cloud sandboxes in one process. Cloud sandboxes support the create, start, get, list, stop, remove, collected exec, and live log streaming operations; streaming exec, attach, metrics, guest filesystem, volumes, snapshots, and bounded log snapshots remain local-only for now. ```python theme={null} from microsandbox import Sandbox, set_default_backend set_default_backend("cloud", profile="prod") async with await Sandbox.create("hello", image="python") as sb: output = await sb.exec("python", ["-c", "print('hi from the cloud')"]) print(output.stdout_text) ``` See the [Python SDK reference](/sdk/python/sandbox). **Detached image init entrypoints** `msb run --init auto` now boots Docker-style init entrypoints, including `/init` from s6-overlay images, in both attached and detached runs. Persisted detached sandboxes remember the init entrypoint across restarts, and attached runs stream startup logs while the image's PID 1 takes over the foreground command. Images like `nousresearch/hermes-agent` can be started directly without a separate wrapper. ```bash theme={null} msb run -d --init auto \ --name hermes --replace \ -p 8642:8642 \ nousresearch/hermes-agent \ -- gateway run ``` See the [sandbox commands reference](/cli/sandbox-commands). **Shared microsandbox type packages** A new `microsandbox-types` Rust crate is now the single source of truth for the sandbox spec and related runtime, resource, environment, and log-level types, with a matching type-only `@microsandbox/types` npm package generated from it. SDK and tooling authors can depend on one stable schema instead of redefining sandbox shapes per language, and the embedded `SandboxSpec` in the Rust SDK's `SandboxConfig` flows through the builder, local spawn, exec, attach, SSH, and cloud paths without duplication. See the [SDK overview](/sdk/overview). **Secret substitution through HTTP CONNECT tunnels** Outbound HTTPS that goes through an `HTTPS_PROXY=http://proxy:port` setting is now eligible for secret substitution. The proxy detects guest `CONNECT host:443` requests over plain TCP and hands the inner TLS stream to the existing interceptor, so placeholders inside the tunneled request get substituted and violation actions still apply. CONNECT metadata is validated, only configured target ports are intercepted, and the intercepted TLS ClientHello SNI must match the CONNECT authority before substitution runs. See the [TLS networking guide](/networking/tls). **Plain HTTP secret substitution, opt in per secret** `SecretsHandler` is now wired into the plain-HTTP relay in addition to the TLS path. Plain-HTTP substitution is opt-in per secret via `require_tls_identity(false)`, so existing secrets that require TLS keep their stricter behavior, and violation detection runs across both transports regardless. Server-first protocols such as SSH, SMTP, and databases are no longer delayed by the substitution layer, and full HTTP header blocks are read across TCP segments so host-scoped secrets match reliably. See the [secrets guide](/security/secrets). **Other features** * **Byte-stream agent client transport.** The `microsandbox-agent-client` crate gains a `stream` feature with `connect_stream`, `connect_stream_with_timeout`, and `connect_stream_with_deadline`, so callers can drive an `AgentClient` over any `AsyncRead + AsyncWrite` they have already authenticated, such as a `Bearer`-authenticated relay connection. The existing UDS transport now layers on top of the same code path. See the [Rust agent client reference](/sdk/rust/agent-client). * **CONNECT secret boundary hardening.** Proxy metadata is parsed and buffered before the upstream dial, placeholders inside outer CONNECT headers are blocked, non-intercepted target ports stay opaque, and encoded body paths that cannot be safely rewritten now block instead of forwarding placeholders unchanged. ## Bug fixes * Snapshot archive import now stages contents in a temporary directory, validates entry types, paths, image metadata, and cache digests, and rejects bundles whose manifest paths escape the artifact directory or whose resolved image digest does not match the snapshot pin. * IPv6 addresses inside the virtual network no longer get stuck in the `tentative` state, so guests with IPv6-capable hosts can send outbound IPv6 traffic instead of having the kernel drop it. * Memory metrics for idle sandboxes are now sourced from paced balloon stats, so an idle sandbox no longer pins a host core through the old virtio-balloon busy-spin path. * Sandbox names longer than 64 bytes no longer fail to boot with `sethostname: EINVAL`. The spawn path now derives a UTS-compatible 64-byte hostname when none is set explicitly, and the 128-byte sandbox name limit still applies. * `VolumeFs::remove_dir("/")` and `remove_dir("")` no longer delete the host-side backing directory for the entire volume; only child directories inside the volume can be removed. * Outbound proxy connections that are denied by SNI policy now close the guest socket cleanly instead of leaving clients like `wget` stuck until the host timeout fires. Upstream connect failures still RST the guest socket so clients fail fast. * `msb run --init auto` against images that ship an `ENTRYPOINT` init binary now preserves the user command through PID 1 instead of double-execing the wrapper after boot, and streams startup output back to attached runs. # Week of June 26, 2026 Source: https://docs.microsandbox.dev/changelog/2026-06-26 Windows host support, guest-write quotas for virtiofs mounts, host-directory bind rootfs across all SDKs, non-PTY bidirectional `exec --stream`, upper disk usage metrics, an `msb doctor` command, runtime-owned ephemeral cleanup, and a round of SDK and runtime fixes. **Released this week:** [v0.5.8](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.8) · [v0.5.10](https://github.com/superradcompany/microsandbox/releases/tag/v0.5.10) · [v0.6.0](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.0) ## New features **Windows host support** Microsandbox now runs as a first-class local host on Windows on top of the libkrun and libkrunfw Windows ports. The `msb` CLI, installer, runtime, networking, filesystem, image, and SDK packages all build and run natively, including a Windows-specific passthrough filesystem backend, interactive SSH attach, and a release installer flow. Pieces that still depend on Unix-only behavior surface as explicit unsupported errors instead of silently misbehaving, and Windows SDK packages are now published alongside the macOS and Linux artifacts. ```bash theme={null} msb run --name devbox -p 8080:8080 python:3.12 ``` See the [quickstart](/getting-started/quickstart). **Guest-write quotas for virtiofs mounts** `PassthroughFs` now caps how much a guest can write to a virtiofs mount, so a sandbox can no longer fill the host disk through `/.msb` or a bind mount. The runtime directory is held to a 16 MiB control-channel cap, bind mounts default to a 4 GiB guest-write quota that can be overridden per mount, and named directory volumes now enforce their existing `quota_mib` setting. Enforcement charges only new file growth, never pre-existing content, and guest `df` reports the budget rather than the host's full disk. ```bash theme={null} msb run alpine \ --mount-dir ./workspace:/work:rw,quota=1G ``` See the [volumes guide](/sandboxes/volumes). **Host-directory bind rootfs across all SDKs** `RootfsSource::Bind` is now a first-class SDK option in Rust, Go, TypeScript, and Python, so a sandbox can boot directly off a host directory with no OCI pull and no overlay. The Python SDK already exposed `ImageSource.bind`; this brings the other languages to parity with `ImageBuilder.bind(host)` in Rust and TypeScript, and `WithBindRootfs(path)` in Go. ```python theme={null} from microsandbox import Image, Sandbox async with await Sandbox.create( "dev", image=Image.bind("/srv/rootfs/python-base"), ) as sb: output = await sb.exec("python", ["-c", "print('hello from bind rootfs')"]) print(output.stdout_text) ``` See the [Python images reference](/sdk/python/images). **Non-PTY bidirectional `msb exec --stream`** `msb exec` gains a `--stream` flag that streams stdin and stdout bidirectionally with no PTY and no buffering. The default `exec` path still reads stdin to EOF and buffers output until the command exits, and `-t/--tty` still allocates a PTY with echo and CRLF translation; `--stream` is the option for driving a long-lived guest process turn by turn, such as a JSON-lines protocol where each request depends on the previous response. ```bash theme={null} msb exec worker --stream -- node repl.js ``` See the [sandbox commands reference](/cli/sandbox-commands). **OCI upper disk usage metrics** Sandboxes booted from an OCI image now publish live metrics for the writable upper layer: `upper_used_bytes`, `upper_free_bytes`, and `upper_host_allocated_bytes`. The fields flow through `msb metrics --format json`, the Rust, TypeScript, Python, and Go SDKs, and `msb-metrics` OTel gauges (`microsandbox.upper.used`, `microsandbox.upper.free`, `microsandbox.upper.host_allocated`), so capacity dashboards can track the writable overlay without parsing the live ext4 image. See [Observability](/observability/msb-metrics#metrics). **Other features** * **`msb doctor` host readiness check.** A new top-level `msb doctor` command runs the host readiness check from the CLI's main help, alongside the existing `msb self doctor` and `msb self check` forms. On Windows hosts the doctor also offers a fix flow for the Windows Hypervisor Platform feature. See the [CLI overview](/cli/overview). * **Runtime-owned ephemeral sandbox cleanup.** Unnamed `msb run` sandboxes, including detached runs, are now marked ephemeral and cleaned up by the host runtime after the VM exits, with a coordinated sweep for stale rows and missed cleanup at runtime startup. Named runs and `msb create` sandboxes stay persistent. The Rust SDK exposes the same control through `Sandbox::builder(...).ephemeral(true)`. See the [sandbox lifecycle guide](/sandboxes/lifecycle). * **Per-secret CONNECT proxy substitution.** Secret substitution now works when the guest reaches an upstream through an HTTP CONNECT proxy (`HTTPS_PROXY=http://proxy:port`). The proxy uses the CONNECT authority and ClientHello SNI cross-check it already performs to skip the DNS-cache pin that the tunneled path could not satisfy, so placeholders are substituted inside the inner TLS stream as expected. See the [TLS networking guide](/networking/tls). * **Loopback default for published ports, with explicit warning on host exposure.** Published ports still default to loopback bindings, but wildcard and concrete non-loopback binds now emit a warning at run time because they can be reachable beyond `localhost` and may trigger a Windows Defender Firewall prompt. See the [sandbox commands reference](/cli/sandbox-commands). * **Slimmer `msb sandbox` argv.** The sandbox launcher no longer puts the full network config and environment on argv, where they showed up in `ps` and host logs and risked leaking guest secrets through `/proc//cmdline`. Operator-readable labels (name, sandbox id, vcpus, memory, log level) stay on argv; everything bulky or secret-bearing now travels through an inherited config fd. ## Bug fixes * Named volumes created with `kind=disk` are now mounted as a virtio-blk block device again, so overlayfs and Docker-in-VM workloads no longer fail with `EINVAL`. The disk kind is also recovered from the volume store, so the fix survives a sandbox restart. * Live sandbox lifecycle methods are restored across the Rust, TypeScript, Python, and Go SDKs, so callers can stop, kill, drain, and wait on the sandbox handle they already have. Node `Sandbox.list()` and `Sandbox.listWith()` again return usable sandbox handles instead of inert listings. * Named volume semantics are restored after the local and cloud backend split: disk-backed named volumes attach as block devices, directory-backed named volumes stay on virtiofs, lifecycle locks are held through create, and Go, Node, and Python bindings line up with the restored behavior. * `msb stop` and attach sessions against a runtime that has already exited as a zombie no longer hang. Zombie PIDs are treated as dead in the SDK and runtime startup maintenance, stale `Draining` runtimes reconcile to `Stopped`, and a closed relay receiver exits the attach session instead of silently swallowing stdin. * Detached `msb run -- CMD` no longer drops the command. The command is persisted as runtime-owned startup intent, executed by the host runtime after agentd is ready, and the VM shuts down when the workload exits. Known image init entrypoints under `--init auto` also receive the image entrypoint tail plus the effective command, environment, and workdir. * The agent heartbeat watchdog no longer kills healthy sandboxes after a few minutes when the heartbeat goes briefly stale. The monitor is idle-detection only; genuine boot failures are still reclaimed through the relay `wait_ready` timeout, and the guest writes its heartbeat from a dedicated OS thread so a saturated agent runtime cannot starve idle detection. * Setting `disk_size` on a bind or disk-image rootfs is now a logged warning instead of a hard build error. The field only sizes the OCI writable overlay, so it is ignored for non-OCI rootfs sources without failing the build. * `Draining` sandboxes without any active runs are now treated as terminal during reconciliation, so `stop` callers no longer poll forever when the runtime has already exited. The smoltcp TX backend also drops frames when its ring is full instead of waiting on readiness that can never signal queue capacity. # Week of July 5, 2026 Source: https://docs.microsandbox.dev/changelog/2026-07-05 Modify existing sandboxes, inspect resize headroom, trust private TLS upstreams, load images faster, and pick up CLI, network, and SDK fixes. **Released this week:** [v0.6.1](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.1) · [v0.6.2](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.2) · [v0.6.3](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.3) · [v0.6.4](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.4) ## New features **Modify existing sandboxes** `msb modify` and the SDK modify APIs can update existing sandboxes without recreating them. Resize CPU and memory, update labels, set env vars or workdir for future execs, and preview the plan with `--dry-run`. Secret changes are available in the CLI and Rust SDK. ```bash theme={null} msb modify worker --cpus 2 --memory 1G --dry-run msb modify worker --secret DB_URL@db.internal.example.com ``` See [Live Modify](/sandboxes/tuning). Also new: `msb restart`, `msb touch`, and `msb ping`. **Inspect allocation and metrics** `msb ps` now shows CPU and memory as `effective / max`. `msb metrics` adds sandbox state, per-second I/O rates, sorting, live watch/follow modes, and live-resize-aware CPU and memory readings. ```bash theme={null} msb ps msb metrics --watch --sort cpu ``` Crashed sandboxes now report as `exited` instead of `running`. The Rust SDK exposes the same report through `SandboxMetricsReport`. **Host-scoped upstream TLS trust** Trust self-signed or private HTTPS upstreams without disabling secret substitution globally. Pin a CA bundle to specific hosts, or turn verification off for a bounded set of hosts. Available in the CLI and all four SDKs. ```bash theme={null} msb create python --name agent \ --tls-intercept \ --tls-upstream-ca-cert-for 'api.internal.example.com=./certs/api-ca.pem' \ --tls-no-verify-upstream-for '*.preview.internal' ``` See the [TLS networking guide](/networking/tls). **Faster `msb load` and `msb pull`** Loading an image that is already on disk now takes under a second instead of around 20 seconds for a 1.3 GB image. `msb load` also shows progress while streaming from Docker. ```bash theme={null} docker save app:latest | msb load ``` `msb-imago` 0.1.1 also fixes OCI image corruption for layers over 2 GiB. **Other features** * **`msb self downgrade`.** Move a local install back to version 0.6.0 or newer, with database backup and migration rollback. * **`--no-tty`.** Force non-interactive captured execution in `msb run` and `msb exec`. ## Bug fixes * `msb exec` now signals the full guest process group, so spawned background jobs do not survive as orphans. * Large and fragmented UDP packets now round-trip through the relay; IPv6 DNS answers, IPv4-mapped addresses, and generated network config files are also handled more reliably. * `msb stop` no longer reports `sandbox not found` when an ephemeral sandbox is cleaned up during the stop wait. * `MSB_SHUTDOWN_FLUSH_TIMEOUT_MS` can shorten shutdown waits for Windows WHP tests and short-lived sandboxes. * SSH `direct-tcpip`, image prune behavior, and Rust default-backend helpers are restored after backend-routing regressions. * `msb doctor` now uses the same runtime path resolution as sandbox launches, and top-level `msb --help` no longer prints raw ANSI escapes on older Windows consoles. # Week of July 10, 2026 Source: https://docs.microsandbox.dev/changelog/2026-07-10 Structured root disk for OCI sandboxes, default symlink protection on mount roots, secret modify across every SDK, offline OCI upper growth, cleaner guest shutdown, and a batch of snapshot, filesystem, and lifecycle fixes. **Released this week:** [v0.6.6](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.6) ## New features **Structured root disk for OCI sandboxes** The writable layer of an OCI sandbox is now a first-class "root disk" with three backings: the managed sparse ext4 upper (default, unchanged), a RAM-backed `tmpfs` that gives you a pristine rootfs on every boot, and a user-supplied disk image attached writable. The old `--oci-upper-size` and `upper_size` spellings still work as deprecated aliases. ```bash theme={null} # managed (default, 4 GiB), same as before msb run python --root-disk 8G # RAM-backed, pristine rootfs on every boot msb run python --root-disk tmpfs:2G # user-supplied writable image msb run python --root-disk ./scratch.qcow2:format=qcow2,fstype=ext4 ``` `msb modify --root-disk` keeps grow-only semantics for managed disks, allows any direction for tmpfs, and rejects sizing on user disk images. All four SDKs expose the new surface with builders and deprecated aliases mapping to the managed kind. See the [Live Modify guide](/sandboxes/tuning). **Default symlink protection on mount roots** Every bind volume and bind rootfs now resolves its root without following symlinks and without accepting `..`, so a symlink planted at a mount root cannot redirect a sandbox out of its intended host directory. Protection is on by default for every user mount, with a per-mount `follow-root-symlinks` opt-out for host paths that legitimately traverse a symlink. ```bash theme={null} # protected by default: a symlink at the mount root is refused msb run alpine -v /vol/tenant-a/work:/mnt -- ls /mnt # opt out per mount when the host path is a symlink on purpose msb run alpine -v /vol/tenant-a/link:/mnt:follow-root-symlinks -- ls /mnt ``` Relative bind paths keep working. A one-time migration rewrites persisted bind rootfs configs to the new object shape. See the [volumes guide](/sandboxes/volumes). **Secret modify parity across every SDK** Rotating and removing secrets on a live sandbox is now available in the TypeScript, Python, and Go SDKs, matching what the Rust SDK and `msb modify --secret` already offered. Each SDK's modify options accept a declarative `secrets` map with `env` / `value` / `store` sources, an optional placeholder, and allowed hosts, plus `secretsRemove` for removals. Raw secret values never appear in plans, errors, or test output. See [Secrets](/sandboxes/secrets). **Offline OCI upper growth** `msb modify --oci-upper-size` and the new `--root-disk` size form now grow the writable ext4 upper without `resize2fs` or any external tooling. A pure-Rust resizer handles this on macOS, Linux, and Windows hosts. New images reserve about 2 TiB of growth headroom; older images can still grow within their existing slack. Stopped sandboxes grow before the size is persisted, running sandboxes grow via `--restart` or on the next start with `--next-start`, and shrink is rejected. Growth includes crash-safe ordering and journal replay for images that were mounted before, so a fresh grow is safe even without a clean guest shutdown. **Clean guest shutdown** `msb stop` and other graceful shutdowns now unmount guest filesystems before power-off, so the writable ext4 upper no longer carries a dirty journal after every run. The teardown pins the upper's directory before the guest pivots, syncs and quiesces writers, and remounts the upper read-only within the host's shutdown window. Data is unchanged; subsequent boots and image grows start from a clean journal. **`update`, `upgrade`, and `downgrade` at the top level** `msb update`, `msb upgrade`, and `msb downgrade` are now top-level aliases for the existing `msb self update` and `msb self downgrade` flows. They match the shorter commands you already reach for from other package managers. See the [CLI overview](/cli/overview). **Other features** * **Live control over a named pipe on Windows.** The host runtime now serves its live control channel through a Windows named pipe on Windows hosts, so live-attach, `msb exec`, and lifecycle calls work on Windows the same way they do on Unix sockets elsewhere. * **Sparse tar entries for snapshot exports.** `msb snapshot save` now stores files that contain runs of zeros as GNU sparse tar entries, so exported archives of sandboxes with large sparse files are meaningfully smaller and faster to write. Standard `tar` reads them back transparently. See [Snapshots](/sandboxes/snapshots). ## Bug fixes * Windows sandbox teardown no longer leaves the runtime process alive when Windows Hypervisor Platform shutdown stalls. `msb stop`, `msb kill`, and `msb remove` now verify the process identity by creation time and image name before terminating it. Recycled PIDs are never touched, and future same-named sandboxes reach a fresh VM instead of a stale named pipe. * Passthrough virtiofs mounts survive host file-descriptor exhaustion. Large directory listings and heavy concurrent I/O no longer stall the sandbox when the host runs out of open file slots. * `msb exec` no longer stalls on very large directories. `readdir` results are streamed page by page instead of collected into a single response, so listing directories with many entries returns promptly. * Guest paths in the SDKs are now typed as plain strings, so paths sent from a Windows host to a Linux guest are no longer mangled by host path rules. Existing callers that were already passing strings continue to work; typed `Path` values must be converted to strings. * `msb snapshot restore` now checks the local snapshot cache before hitting the registry, so restores are fast and work offline when the base image is already on disk. * `msb snapshot restore` also pins snapshots to an immutable content digest instead of the mutable tag, so restoring a snapshot returns the exact base that was captured even if the tag has since moved. # Week of July 17, 2026 Source: https://docs.microsandbox.dev/changelog/2026-07-17 Image archives on every SDK, a finalized snapshot API with dest_dir and --from-snapshot, hole-perfect snapshot archives across platforms, a newer guest kernel, and a batch of secret, snapshot, and SDK fixes. ## New features **Image archives on every SDK** Local image archives (`docker save` tarballs and OCI Image Layout) can now be imported and exported from the Python, TypeScript, and Go SDKs, matching what `msb image load` / `msb image save` and the Rust SDK already offered. `Image.load` accepts an optional tag and, in Python, reads from stdin when the path is `-`. `Image.save` accepts a single reference or several references bundled into one archive, and writes either Docker or OCI format. ```typescript theme={null} // docker save my-image:latest -o my-image.tar const images = await Image.load("my-image.tar", { tag: "app:local" }); await Image.save(["python:3.12", "app:local"], { outputPath: "bundle.tar", format: "oci", }); ``` ```python theme={null} await Image.load("my-image.tar", tag="app:local") await Image.save(["python:3.12", "app:local"], output_path="bundle.tar") ``` ```go theme={null} _, err := microsandbox.Image.Load(ctx, "my-image.tar", "app:local") err = microsandbox.Image.Save( ctx, []string{"python:3.12"}, "python.tar", microsandbox.ImageArchiveDocker, ) ``` See the [images guides](/sdk/python/images) for each SDK. **Snapshot API contract finalized** The snapshot surface is now locked in across the CLI and every SDK ahead of 1.0. `snapshot.json` is the only descriptor, `save` and `load` are the archive verbs, and `reindex` is the maintenance verb. Snapshot creation is name-first with a required source, and a new optional `dest_dir` (CLI `--dest-dir`) places the artifact on another volume without changing its identity. Booting from a snapshot is spelled the same way everywhere: `--from-snapshot`, `from_snapshot=`, `fromSnapshot`, and Go `WithFromSnapshot`. ```bash theme={null} msb snapshot create clean --from-sandbox box --dest-dir /mnt/big msb snapshot save clean /tmp/clean.tar.zst --with-image msb snapshot load /tmp/clean.tar.zst msb run --name worker --from-snapshot clean -- python -V ``` This is a breaking change for pre-1.0 callers: `msb run --snapshot` becomes `--from-snapshot`, `Sandbox.create(snapshot=)` becomes `from_snapshot=`, the Go `WithSnapshot` option is renamed to `WithFromSnapshot`, and the `SnapshotDestination` / `snapshot_to` shapes are removed. Legacy `manifest.json` artifacts are no longer readable. See [Snapshots](/sandboxes/snapshots). **Hole-perfect snapshot archives on every platform** `msb snapshot save` and `msb snapshot load` now preserve sparse regions end to end on macOS, Linux, and Windows. Export scans the writable upper's allocation map (SEEK\_DATA/SEEK\_HOLE on Unix, FSCTL\_QUERY\_ALLOCATED\_RANGES on Windows) and writes only the data extents; import restores the file with holes intact on APFS, ext4, and NTFS. A round trip of a 4 GiB upper with 3 MiB allocated produces a 3 KiB archive and re-imports with the same allocation, byte-exact. ```bash theme={null} msb snapshot save clean /tmp/clean.tar.zst msb snapshot load /tmp/clean.tar.zst ``` See [Snapshots](/sandboxes/snapshots). **Other features** * **Multiple hosts on one CLI secret.** `--secret 'ENV@host1,host2'` now attaches one placeholder to a comma-separated list of allowed hosts, so a single secret rule can cover several upstreams. See [Secrets](/sandboxes/secrets). * **Newer guest kernel.** The vendored libkrunfw is now 5.6.0 and boots Linux 6.12.95 in the guest. The libkrunfw ABI stays at version 5, so nothing on the host side changes. * **`MountOptions.QuotaMiB` in the Go SDK.** Go callers can now set a bind-mount write quota through `MountOptions.QuotaMiB`, matching the CLI and Rust SDK. Unset keeps the protective 4 GiB default. See the [Go volumes guide](/sdk/go/volumes). ## Bug fixes * The Node SDK now works from CommonJS: `require("microsandbox")` resolves on Node 20.19+, Node 22+, and Bun instead of failing with `ERR_PACKAGE_PATH_NOT_EXPORTED`. ESM consumers are unaffected. * Repeated `--secret ENV@HOST` rules that share the same placeholder no longer block a request when only some of the rules match the current host. The non-matching duplicates are filtered before substitution. * Snapshotting a sandbox whose root disk is tmpfs or a user-supplied disk image now fails with a clear message explaining why, instead of the raw `has no upper.ext4` error. Managed root disks are unaffected. * The Go SDK bind path now forwards `quota_mib` through the FFI layer, so `MountOptions.QuotaMiB` is honored end to end. Callers who did not set a quota still get the protective 4 GiB default. # Week of July 24, 2026 Source: https://docs.microsandbox.dev/changelog/2026-07-24 Composable network profiles across CLI and SDKs, bidirectional snapshot migration with msb self downgrade, msb run -d that honors image CMD, TTY resize in every SDK, and Go SDK on Windows. **Released this week:** [v0.6.7](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.7) ## New features **Composable network profiles** Network policy is now built from named profiles instead of ad-hoc presets. Pass one or more of `public`, `private`, and `host` to `--net` on the CLI, or to `NetworkPolicy.from_profiles()` / `fromProfiles()` / `FromProfiles()` in the SDKs. `--net` is repeatable and accepts a comma-separated list, plus the terminal values `all` and `none`. Explicit `--net-rule` entries keep first-match precedence and now understand `allow@dns` / `deny@dns` targets, so DNS answers are policy-aware instead of implicitly allowed. The IPv4 and IPv6 unspecified addresses are excluded from `public`, closing a DNS-rebinding gap. This is a breaking change for pre-1.0 callers: the legacy `public_only` and `non_local` presets are removed. Migrate to the `public` profile or the CLI equivalent. ```bash theme={null} msb run --net public,private --net-rule 'allow@dns' python ``` ```python theme={null} from microsandbox import NetworkPolicy, NetworkProfile policy = NetworkPolicy.from_profiles([ NetworkProfile.PUBLIC, NetworkProfile.PRIVATE, ]) ``` ```typescript theme={null} import { NetworkPolicy } from "microsandbox"; const policy = NetworkPolicy.fromProfiles(["public", "private"]); ``` See the [networking overview](/networking/overview). **Bidirectional snapshot migration with `msb self downgrade`** Microsandbox now treats snapshots created on v0.6.6 and v0.6.7 as fully interchangeable. It migrates older `manifest.json` artifacts to the finalized `snapshot.json` descriptor on startup, explicit open, reindex, and archive load, enforces sparse payload integrity, and rejects duplicate keys. It also retains the original descriptor bytes so a downgrade produces the exact prior artifact. `msb self downgrade 0.6.6 --yes` performs a durable, journaled downgrade with SHA-256 verification and a database backup. If the process is interrupted, startup refuses to continue until recovery finishes, so you cannot end up with a half-migrated store. Each SDK also exposes the new projections, so tooling can tell the current snapshot state and any pending migration apart. In Rust these are `Snapshot::state_kind()` and `migration_state()`; in Python, `snapshot.state_kind` and `snapshot.migration_state`; in TypeScript, `.stateKind` and `.migrationState`; in Go, `.StateKind()` and `.MigrationState()`. Migration errors now surface as a dedicated `SnapshotMigration` error kind (Python `SnapshotMigrationError`). ```bash theme={null} msb self downgrade 0.6.6 --yes ``` See [Snapshots](/sandboxes/snapshots). **`msb run -d` honors the image CMD** Detached runs now resolve and launch the same OCI command as an attached `msb run`. If you omit the command, the image's CMD is used; if you pass a command after `--`, it replaces CMD while the image's entrypoint is preserved. Previously, `msb run -d` would boot the sandbox without executing the image's default process, which surprised users running images like `docker:dind`. For an idle sandbox you can `exec` into later, use `msb create` instead. Both flows are documented under [Sandbox commands](/cli/sandbox-commands). ```bash theme={null} msb run -d --script start='exec dockerd' --entrypoint start docker:dind msb create --name devbox python msb exec devbox -- python -c "print('hello')" ``` **Other features** * **TTY resize in the Python, TypeScript, and Go SDKs.** `ExecHandle.resize(rows, cols)` (Go: `Resize(ctx, rows, cols)`) is now available on every SDK, matching the existing Rust API. Signal, kill, and resize operations run through cloneable exec controls, so they work while a `recv()` is pending. This is what interactive proxies and remote-terminal integrations need. See the [Python execution guide](/sdk/python/execution). * **Go SDK on Windows.** The Go SDK now builds and runs on Windows amd64 and arm64. Installation downloads the Windows release bundle, uses `msb.exe` and `libkrunfw.dll`, and skips Unix-only symlinks. Home directories with non-ASCII characters are handled correctly. See the [Go SDK installation guide](/sdk/go/sandbox). * **`status_reason` on cloud sandbox responses.** While a cloud sandbox is `starting`, the response includes a machine-readable `status_reason` of `scheduling` or `insufficient_capacity`. Clients can now distinguish "waiting in the scheduler" from "no capacity" without parsing prose. The human-readable field is renamed from `last_error` to `last_failure_message` to make the split between machine enums (`*_reason`) and prose (`*_message`) consistent. Rust callers should rename `Sandbox::last_error()` to `Sandbox::last_failure_message()`, and `SandboxHandle::last_error_snapshot()` to `last_failure_message_snapshot()`. ## Bug fixes * The install script now discovers the exact libkrunfw filename and ABI packaged in each release bundle instead of using hardcoded pins. This prevents the installer and the release artifact from drifting apart, and rejects bundles with missing or malformed versioned library names. The Windows installer is unchanged. * The Python SDK once again imports on Python 3.10. Typed enums that regressed 3.10 compatibility have been rewritten to work on the older runtime. # Week of July 31, 2026 Source: https://docs.microsandbox.dev/changelog/2026-07-31 Unified cloud backend in every SDK with paginated sandbox listings, per-registry insecure and custom-CA overrides in Go and Python, msb completion for shell tab-completion, a shared log registry for tailing many sandboxes, and fixes for guest TCP half-close, DNS upstream failover, and cloud exec reconnects. **Released this week:** [v0.6.8](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.8) ## New features **Unified cloud backend across every SDK** The Rust, Python, TypeScript, and Go SDKs now share one public sandbox and volume API across local and cloud backends. Set `MSB_API_KEY` (and, if you self-host, `MSB_API_URL`), and the same `Sandbox.create(...)` you already use for local sandboxes now handles create, exec, SSH, filesystem operations, and volume management against the hosted service. Hosted usage defaults to `https://api.microsandbox.dev`. Only the API key selects the cloud backend, so setting `MSB_API_URL` on its own keeps you on the local backend. ```bash theme={null} export MSB_API_KEY="msb_ak_..." ``` ```python theme={null} import asyncio from microsandbox import Sandbox async def main() -> None: sandbox = await Sandbox.create("sdk-demo", image="alpine:3.19") try: result = await sandbox.shell("echo hello from microsandbox") print(result.stdout_text, end="") finally: await sandbox.stop() await Sandbox.remove("sdk-demo") asyncio.run(main()) ``` `Sandbox.list` now returns a bounded `SandboxPage` with an opaque cursor, a page limit, and label filters. The default `list()` call is unchanged for quick use; larger or filtered scans use each language's `list_with` configuration form. This is a breaking change for callers that expected an unbounded list. **Per-registry insecure and custom-CA overrides in Go and Python** The Go and Python SDKs can now pull from a plain-HTTP registry or one using a private CA without host-level configuration. Both surfaces mirror the Rust and TypeScript builders. ```python theme={null} sb = await Sandbox.create( "worker", image="localhost:5050/my-app:latest", registry_insecure=True, registry_ca_certs=["/etc/ssl/private-ca.pem"], ) ``` ```go theme={null} sb, err := m.CreateSandbox(ctx, "worker", m.WithImage("localhost:5050/my-app:latest"), m.WithRegistryInsecure(), m.WithRegistryCACertsPath("/etc/ssl/private-ca.pem"), ) ``` CA-cert paths are read at create time, so an unreadable file fails immediately instead of mid-pull. See the [images overview](/images/overview). **`msb completion` for shell tab-completion** `msb completion ` prints a completion script for `bash`, `zsh`, `fish`, `elvish`, or `powershell` to stdout, so you or a packager can wire up tab completion without a helper package. ```bash theme={null} msb completion zsh > "${fpath[1]}/_msb" ``` See the [CLI overview](/cli/overview). **Other features** * **Shared log registry for many followed streams.** A new `LogRegistry` lets a single process tail logs from many sandboxes at once without exhausting the OS watcher quota. One watcher is shared across every followed stream, so processes that would previously hit `fs.inotify.max_user_instances` on Linux (default 128) now scale to many more sandboxes. Use `Sandbox::logger()` to get a `SandboxLogger` you can register with the shared registry. Standalone `log_stream(follow = true)` behavior is unchanged. ## Bug fixes * Long-lived proxied TCP connections no longer leak connection-table slots when the guest closes cleanly. A guest FIN is now propagated to the upstream write half instead of leaving the smoltcp socket in `CLOSE_WAIT` forever. Previously, on sandboxes whose upstreams do not idle-close, the 256-slot connection table filled up and guest egress went dark until the sandbox was restarted. Legal TCP half-close is preserved, so a guest that does `shutdown(SHUT_WR)` and then reads still receives a server response. * Two follow-up half-close races are also fixed: connections that reach `CLOSE_WAIT` before the proxy task is spawned are handed off correctly, and pending DNS-over-TLS responses are preserved after the guest sends EOF. * DNS resolution now fails over to later upstreams when the first is unreachable. The forwarder previously kept only the first configured upstream, so a broken first nameserver made every lookup fail even when a later server was healthy. Each configured upstream is now tried in order and moves on after a per-query timeout or transport failure. Answers that arrive, including `SERVFAIL` and `REFUSED`, are treated as answers and do not trigger a retry against the next server. * `msb exec` and `msb ssh` now work against running cloud sandboxes. Previously the CLI could not reopen an authenticated agent connection to a hosted sandbox for exec, SSH, or filesystem operations. Cloud reconnect no longer requires OpenSSL on the host. * The Python SDK now correctly disambiguates inline PEM `bytes` from PEM file paths in `registry_ca_certs`, so inline certificate data is not mistakenly interpreted as a filename. # Week of August 7, 2026 Source: https://docs.microsandbox.dev/changelog/2026-08-07 A first-class Ruby SDK, flat OCI root disks, deployment profiles, default-workload execution, host performance improvements, cloud volume filesystem access, and reliability fixes. ## New features **Ruby SDK** microsandbox now ships a first-class Ruby 3.1+ gem backed by a native Magnus extension. The SDK covers sandbox lifecycle, exec and shell, guest filesystem, logs, metrics, images, volumes, snapshots, SSH exec, and explicit local or cloud backend selection. It supports default-deny network allowlists and hostname-scoped secret injection, releases Ruby's GVL around blocking calls, and rebuilds the native runtime after `fork(2)` so Puma, Resque, and Solid Queue process models are safe. ```ruby theme={null} require "microsandbox" Microsandbox::Sandbox.with("worker", image: "alpine:3.19") do |sb| result = sb.shell("echo hello from ruby") puts result.stdout end ``` **Flat OCI root disks** Sandboxes can now boot from a single ext4 root disk materialized directly from an OCI image, in addition to the default layered EROFS plus OverlayFS. Flat root disks skip the overlay stack at runtime, produce a resizable ext4 filesystem, and are content-addressed and cached across sandboxes. `msb pull IMAGE --materialize layered|flat|all` prepares either or both compositions, and the new `--root-disk flat[:SIZE][,fstype=ext4][,clone=auto|copy|reflink]` selects the flat backing at create time. The option is exposed in every SDK. ```bash theme={null} msb pull python:3.12 --materialize flat msb run --root-disk flat:8GiB python -- python -V ``` See the [sandboxes overview](/sandboxes/overview). **Single- and multi-tenant deployment profiles** A new `DeploymentProfile` sits alongside the existing in-guest security profile and is available in Rust, Python, TypeScript, Go, and the CLI. `SingleTenant` preserves the requested local runtime configuration. `MultiTenant` intersects tenant policy with a host-owned public-network floor. The floor blocks private, loopback, link-local, multicast, metadata, and host destinations across TCP, UDP, ICMP, and DNS. It also forces DNS rebinding protection, disables tenant nameserver and interface overrides, prevents host CA import and published host ports, and caps concurrent connections. Tenant policy can still narrow the remaining public space but cannot broaden the floor. ```python theme={null} from microsandbox import DeploymentProfile, Sandbox sb = await Sandbox.create( "job", image="alpine:3.19", deployment_profile=DeploymentProfile.MULTI_TENANT, ) ``` **Explicit default-workload execution** `Sandbox.create(...)` is now strictly boot-only in every SDK. To run the image's resolved OCI `ENTRYPOINT` and `CMD`, use the new default-workload APIs: buffered, streaming, and interactive variants across Rust, Python, TypeScript, and Go. The CLI and runtime share one argv resolver, and `msb run IMAGE -- ...` still performs a one-shot `CMD` override. ```typescript theme={null} const sandbox = await Sandbox.builder("worker") .image("example/worker:latest") .cmd(["worker.py", "--once"]) .create(); const output = await sandbox.execDefault(); ``` **Integrated host performance stack** Sandboxes now use a measured performance stack by default. Topology-aware CPU placement (`inherit`, `auto`, `spread`, `compact`), per-sandbox guest transparent-huge-page policy, x2APIC and AMD AVIC / Intel APICv integration, and bounded buffered block writeback are exposed across the CLI and Rust, Python, TypeScript, and Go SDKs. Linux gets an automatic per-disk writeback window capped at 1536 MiB and scaled to a bounded host-global admission pool; macOS and Windows keep their existing platform behavior. `msb doctor` gains platform-gated root-clone, AVIC, and APICv guidance without changing privileged host policy on its own. **Cloud filesystem access on default volumes** `Volume.get_default` is now available on the cloud backend in every SDK, and the full `VolumeFs` surface works against cloud default and managed directory volumes: read, write, streaming read and write, list, stat, exists, mkdir, remove, copy, and rename. Cloud filesystem requests are routed by immutable UUID rather than mutable display name, so renames no longer race concurrent operations. Local `Volume.get_default` remains explicitly unsupported to avoid accidental host access. See [volumes](/sandboxes/volumes). **Other features** * **Root disk resizing in every SDK.** The TypeScript, Python, and Go SDKs now expose `rootDiskSize` / `root_disk_size` / `RootDiskSizeMiB` on `modify()`, mapped to the canonical `root_disk_size_mib` patch field. Restart and next-start semantics and backing-specific limits are documented in the [Live Modify guide](/sandboxes/tuning). * **Active backend context.** New `default_backend_info()` / `defaultBackendInfo()` accessors, and per-sandbox `backendKind` / `backend_kind` fields, let applications inspect the resolved default backend, its cloud API URL, the selector that chose it, and its profile. The API key is never included. A new `msb context` command prints the same information, and `create`, `remove`, `exec`, and `ssh` show a short backend notice. Invalid cloud CLI configuration now fails closed instead of silently dispatching locally. See [backends](/operations/backends). * **Go SDK: attach as non-default guest users.** The Go SDK gains `AttachWith`, with `WithAttachUser`, `WithAttachCwd`, `WithAttachEnv`, and `WithAttachDetachKeys`, matching the Python and TypeScript surface. The existing `Attach` API is unchanged. See the [Go SDK reference](/sdk/go/execution). ## Breaking changes * **Python SDK closed values are enums.** Backend selection, sandbox modification policy, volume and image configuration, snapshot metadata, network destination discriminators, patch kinds, and log sources now require exported `StrEnum` members instead of raw strings. Native getters return enum members. `SandboxStatus` also gains the runtime's `CREATED` and `STARTING` states. ```python theme={null} from microsandbox import BackendKind, Network, NetworkProfile, set_default_backend set_default_backend(BackendKind.CLOUD) network = Network.from_profiles(NetworkProfile.PUBLIC) ``` * **Explicit cloud backend selection is now required.** Setting `MSB_API_KEY` alone no longer selects the cloud. Cloud intent must be declared through `MSB_BACKEND=cloud`, a selected cloud profile, or a programmatic backend setter. Invalid cloud configuration returns `InvalidConfig` instead of falling back to local execution. See [backends](/operations/backends). ## Bug fixes * Cloud SDK agent WebSockets now trust platform-installed certificate authorities. This restores `msb exec`, SSH, and filesystem operations from nested sandboxes and TLS-inspected environments, where the previous WebPKI-only root store rejected the handshake with `UnknownIssuer` even though HTTPS API calls succeeded. * Cloud log streams now include PTY `output` in the default source set, matching local behavior. Cloud `create` also rejects local-only options that the cloud wire contract cannot preserve, returning the typed `Unsupported(ConfigField)` error instead of silently dropping settings. * Windows read-only file handles no longer return spurious `EACCES` on close over virtiofs. The guest `FUSE_FLUSH` on `close(2)` previously called `FlushFileBuffers` on handles without `GENERIC_WRITE`, which failed with `ERROR_ACCESS_DENIED` and aborted tools like Node's `readFileSync` UTF-8 fast path. Read-only handles now skip flush entirely. * Windows `msb self update` now uses the same deferred scheduled-task swap as `msb self downgrade`, so the running CLI never overwrites itself. Bundles are staged and digest-verified outside the live install, the invoking process is awaited, and the swap retries through Task Scheduler while another process holds an artifact. Repeated PowerShell installs replace files correctly, and a lock failure reports the exact PID before any artifact changes. * `agentd` now has a process-wide child-status owner. Concurrent `exec` sessions no longer lose fast exits to competing waiters, and adopted descendants are reaped instead of accumulating as zombies. Signal termination, spawn failures, pipe and PTY status delivery, and large interleaved output all continue to behave as before. * Per-sandbox metrics gauges no longer accumulate stale sandbox identities. Stopped sandboxes are dropped from OTLP payloads on the next collection, so `msb-metrics` state cannot grow without bound and exceed receiver payload limits. * `Image.inspect` and `msb image inspect --format json` now return the OCI config labels present in the source image. The parser already preserved labels; the database upsert previously discarded them and reported no labels for labeled images. # Week of August 14, 2026 Source: https://docs.microsandbox.dev/changelog/2026-08-14 Per-sandbox network rate limits, NUMA-aware placement profiles, sparse configuration patches with reusable config files, guest-to-host vsock routes, deployment profile from config.json, and reliability fixes across Windows attach, cloud request shapes, image archives, and DNS rules. **Released this week:** [v0.6.9](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.9) ## New features **Per-sandbox network rate limits** Sandboxes can now cap outbound and inbound network traffic independently. Each direction has a bandwidth bucket in bytes and an ops bucket in packets. Buckets start full, refill continuously, and can carry a one-time startup burst that never refills. Limits are set at create time and take effect on the next start. Omitted limits stay unlimited, and rate limits are rejected on cloud sandboxes until the hosted backend supports them. The option is available in the CLI and in the Rust, Python, TypeScript, and Go SDKs. ```python theme={null} from microsandbox import Network, NetworkRateLimiter, RateLimiter, Sandbox, TokenBucket sb = await Sandbox.create( "worker", image="alpine:3.19", network=Network( rate_limiter=NetworkRateLimiter( egress=RateLimiter( bandwidth=TokenBucket(size=10_000_000, refill_time_ms=1_000), ), ), ), ) ``` See the [networking overview](/networking/overview). **NUMA-aware placement profiles** A new host-owned placement profile selects how each sandbox is pinned to CPUs and memory nodes. `prefer_single` co-locates vCPUs and memory on one NUMA node when it fits and falls back to inherited placement when it does not. `strict_single` fails closed if a single node cannot fit the request. `inherit` preserves the existing behavior. `cpu_placement: auto` now spreads across untouched physical cores first, then uses SMT siblings when density requires it, without moving sandboxes that are already running. The runtime also degrades ordinary placement under pressure: `auto`, `spread`, and `compact` share logical CPUs when exclusive capacity is exhausted instead of rejecting new sandboxes. Only `strict_single` remains fail-closed. The selector is available in the CLI and in the Rust, Python, TypeScript, and Go SDKs. macOS supports `inherit` only and fails clearly for managed placement. See [CPU placement](/sandboxes/optimization#cpu). **Sparse configuration files with `--conf`** Sandbox configuration is now a reusable, sparse definition loaded with `msb run`, `msb create`, or `msb install`. Repeatable `--conf`, `--net-conf`, `--resource-conf`, `--runtime-conf`, `--fs-conf`, `--secret-conf`, and `--script-conf` flags compose in exact left-to-right order. Explicit CLI arguments still win. Configuration is never auto-discovered. Scalars and lists replace right-hand-side, and maps merge recursively, so multiple files can complete each other. The Rust SDK exposes typed `SandboxConfigPatch` values and `SandboxBuilder::configure` for the same model. ```bash theme={null} msb run --conf base.yaml --net-conf strict-egress.yaml alpine ``` See [sandbox configuration files](/cli/configuration). **Guest-to-host vsock routes** A process inside a local sandbox can now talk to a host service over virtio-vsock, without opening a TCP port on either side. The host service listens on a Unix stream socket, a Unix datagram socket, or a Windows named pipe, and microsandbox connects it to a fixed guest port. ```bash theme={null} msb run --vsock /run/host-api.sock:5000 alpine msb run --vsock /run/events.sock:5001/dgram alpine ``` Routes are rejected on cloud sandboxes and under the multi-tenant deployment profile. The option is exposed in the CLI and the Rust, Python, TypeScript, and Go SDKs. See [host sockets](/networking/host-sockets). **Other features** * **Deployment profile from `config.json`.** Local host operators can pin every sandbox to `single-tenant` or `multi-tenant` from the global config file. The configured profile is authoritative on create and restart; programmatic backend configuration still takes precedence. Absent or null keeps the previous per-sandbox default. See [configuration](/configuration). * **Live writeback pressure sharing.** Sandboxes with writable disks now start under pressure and converge through weighted fair sharing instead of being rejected when the aggregate writeback pool is full. Every eligible disk gets one fair-share weight, running VMM targets refresh within 250 ms, and reserved writes finish safely before excess dirty ownership retires. Active by default on Linux; a no-op on macOS and Windows. * **Snapshot integrity is opt-in.** Snapshot create, open, boot, save, load, and descriptor-upgrade paths no longer run a hidden BLAKE3 content pass. New snapshots write `integrity: null` by default, and integrity is recorded only when `--integrity` (or `record_integrity`) is set. Released SHA-based descriptors keep their exact readers and verifiers. See [snapshots](/sandboxes/snapshots). ## Bug fixes * Interactive `msb` attach on Windows now renders non-ASCII guest output correctly and forwards typed non-ASCII input as UTF-8. The previous byte-oriented console APIs reinterpreted bytes in the active code page, so characters like `—` printed as `ΓÇö` under `chcp 437`. * Cloud sandbox create requests no longer carry host-only CPU placement, placement profiles, or transparent-huge-page policy. The managed worker applies its own policy, and local configuration keeps all three controls unchanged. * Bind-mount failures now surface a clear "permission denied" error naming the host path, instead of a generic mount error, when a host directory cannot be read. * Image `save` now preserves symbolic-link and hard-link targets longer than the legacy tar 100-byte field. Guest symlink bytes are preserved across Linux, macOS, and Windows hosts. * OCI image layouts whose entrypoint points through one or more nested image indexes now load. Incompatible platforms and unknown media types are skipped, and traversal depth is bounded. * Published-port responses are no longer truncated when the host relay channel applies backpressure. Bytes are retained and retried instead of being consumed and dropped. * `allow@dns` and other qualified DNS network rules now parse in release builds of `msb`. The parser previously depended on a debug-only side effect that was removed in optimized builds. * The Go SDK no longer crashes on macOS when the host process spawns a child after starting a sandbox. Tokio's SIGCHLD handler is now installed with `SA_ONSTACK` on every Unix target, matching Go's cgo signal contract. * Sandbox labels stay consistent across modify, migration, and metrics. Label changes now update the canonical config and the projection atomically, and metrics enrichment refreshes labels from the active config instead of caching them as immutable. * `msb modify` now produces the same `$MSB_` default secret placeholders as `msb create`, and existing placeholders are preserved when rotating secrets. # Week of August 21, 2026 Source: https://docs.microsandbox.dev/changelog/2026-08-21 Configurable SSH inactivity timeout, plural resource list shortcuts, precompiled Ruby platform gems, a fallible lazy local backend builder, faster Windows root-disk copies, and reliability fixes across networking, mounts, runtime bootstrap, and Linux releases. **Released this week:** [v0.6.10](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.10) · [v0.6.11](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.11) · [v0.6.12](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.12) · [v0.6.13](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.13) · [v0.6.14](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.14) ## New features **Configurable SSH inactivity timeout** The SSH inactivity timeout keeps its 10-minute default, but you can now change it. Set `ssh.inactivity_timeout_secs` in the global config, pass `--inactivity-timeout` or `--no-inactivity-timeout` on the CLI, or override it per session in the Rust, TypeScript, Python, and Go SDKs. A value of `0` disables the timeout entirely. The setting is independent of sandbox idle timeouts and only controls how long an idle SSH session stays open. ```bash theme={null} msb ssh worker --inactivity-timeout 1800 ``` See [SSH](/sandboxes/ssh). **Plural resource list shortcuts** Top-level plural aliases now list volumes, snapshots, and configured registries without typing the full ` list` command. `msb volumes` and `msb vols` list volumes, `msb snapshots` and `msb snaps` list snapshots, and `msb registries` and `msb regs` list registries. The shortcuts follow the existing `msb images` convention and accept the same flags as their subcommand counterparts. ```bash theme={null} msb vols --format json msb snaps -q ``` See the [CLI overview](/cli/overview). **Other features** * **Precompiled Ruby platform gems.** `gem install microsandbox` now pulls a prebuilt binary on `x86_64-linux-gnu`, `aarch64-linux-gnu`, and `arm64-darwin` for Ruby 3.1 through 3.4. On those targets you no longer need a Rust toolchain to install. musl, Windows, and other platforms continue to build from source. * **Fallible lazy local backend builder.** The Rust SDK adds `LocalBackendBuilder::try_build_lazy()` so embedding hosts can reject invalid persisted configuration before opening the database. `build_lazy()` keeps its fallback behavior for existing callers. * **`msb mod` alias.** `mod` is now a visible alias for `msb modify`, so quick tweaks are shorter to type. `msb create`, `remove`, `exec`, and `ssh` also stopped printing the active backend before each command. Use `msb context` or `msb ctx` when you want to inspect it. See the [CLI reference](/cli/sandbox-commands). * **Faster Windows root-disk copies.** Cloning sparse root disks on NTFS now copies allocated ranges using `FSCTL_QUERY_ALLOCATED_RANGES` instead of scanning for non-zero bytes. In a measured 10 GiB flat-disk copy on Windows 11 ARM64, the copy went from 271 seconds to a 1.5-second median while preserving sparse output. The non-zero byte scan remains as a fallback when the filesystem cannot expose allocation metadata. ## Bug fixes * Host DNS lookups on Windows now go through the Windows DNS Client instead of flattening servers from every active adapter. This preserves VPN, NRPT, resolver health, and encrypted-DNS behavior, avoids stale servers from Hyper-V and other virtual adapters, and starts on Windows builds that do not export `DnsQueryRaw`. Explicit `--dns-nameserver` values still use the direct resolver path. * `msb modify --root-disk` can grow ext4 upper disks created before v0.6.9. The legacy feature mask is now recognized, damaged or ambiguous layouts are refused before any resize write, and pending journals are replayed before geometry changes. * Failed `msb exec` runs against sandboxes the CLI started no longer leave those sandboxes running. Invalid environment variables, resource limits, and timeouts are also caught before the target sandbox is resolved or started. Sandboxes that were already running stay running. * Bind-mount rootfs patches are now contained inside the configured guest root, including through descendant symlinks and Windows junctions. `replace: false` is now atomic, guest-internal symlink behavior is preserved, and Windows-incompatible modes are rejected before mutation begins. * Guest boot configuration and workload environment values no longer travel on the kernel command line. JSON environment values containing double quotes now survive CLI and SDK launches without appearing in `/proc/cmdline`. * Deferred domain allow rules now require a DNS pin binding before admitting a TCP connect, so unrelated raw IPs no longer look reachable under default-deny policies. Deny-only default-deny policies also stop reporting fake connect success. * Nested guest mount destinations now always mount parent-first. Submitting mounts in arbitrary order, for example through the Go SDK's mount map, no longer lets a child mount be hidden by a later parent. Canonical duplicate destinations are rejected up front. * `host.microsandbox.internal` now reaches host services that only listen on one loopback family. When the matching gateway-family connection is refused or unavailable, the other family is retried across plain TCP, CONNECT, and TLS proxy flows. * Bind-mount permission errors now surface a clear message with the host path instead of failing to build. * The Linux installer now requires glibc 2.28, matching the released artifacts. Every published Linux binary, including `msb`, `msb-metrics`, the Node native binding, and the Go FFI library, is built against glibc 2.28. A CI gate scans raw release files, npm payloads, tarballs, and wheels and fails the release if any required `GLIBC_*` version exceeds 2.28. * Unix Python wheels and release tarballs now ship `msb` with mode `0755`. GitHub artifact transfers were dropping the executable bit, so installed wheels could resolve a non-executable bundled runtime. # Week of August 26, 2026 Source: https://docs.microsandbox.dev/changelog/2026-08-26 Reuse named sandboxes safely across every SDK. ## New features **Reuse named sandboxes** Every SDK now has a connect-or-create operation for reusable sandbox names: `connect_or_create` in Rust, Python, and Ruby, `connectOrCreate` in TypeScript, and `ConnectOrCreateSandbox` in Go. It connects when the sandbox is running, starts it when it is stopped or crashed, and creates it only when the name is unused. Existing sandboxes keep their saved configuration. ```python theme={null} sb = await Sandbox.connect_or_create( "worker", image="python", memory=1024, ) ``` Metadata handles also gain `connect_or_start` and its language-specific equivalents, along with methods for waiting on a state, restarting, and stopping and removing a sandbox. See [Reuse or create a named sandbox](/sandboxes/lifecycle#reuse-or-create-a-named-sandbox). The SDK references show the exact method names for Rust, TypeScript, Python, Go, and Ruby. **Handles stay attached to one sandbox** Live sandboxes and metadata handles now expose a stable ID. Lifecycle calls use that ID, so removing a sandbox and recreating its name cannot redirect an old handle to the replacement. Rust, TypeScript, Python, and Go return typed replacement errors; Ruby reports the same refusal through `Microsandbox::Error`. See [Names, handles, and concurrent callers](/sandboxes/lifecycle#names-handles-and-concurrent-callers) and [Error handling](/sdk/errors#when-a-sandbox-object-is-stale) for details. # Week of August 28, 2026 Source: https://docs.microsandbox.dev/changelog/2026-08-28 Guest ownership for directory mounts, sparse layered sandbox configuration, Go SDK MSB_HOME support, isolated single-file mounts, and fixes for read-only mounts, log retrieval, and network slot exhaustion. **Released this week:** [v0.6.15](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.15) · [v0.6.16](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.16) ## New features **Guest ownership for directory mounts** Bind mounts and directory-backed named volumes can now present their files as a chosen guest `uid`/`gid` pair. Host ownership is untouched; only the guest view changes, and any existing per-file metadata override still wins. Set the pair through the CLI mount options or the mount APIs in the Rust, TypeScript, Python, and Go SDKs. Both IDs must be set together. The option requires stat virtualization, so it cannot be combined with `stat-virt=off`, tmpfs, or disk-backed mounts. ```bash theme={null} msb run python --mount-dir ./workspace:/workspace:uid=1000,gid=1000 ``` See [Fallback guest ownership](/sandboxes/volumes#fallback-guest-ownership). **Sparse layered sandbox configuration** Sandbox configuration now merges by field presence across three layers: built-in defaults, the persisted global config, and per-sandbox settings, in that precedence order. Config files passed to the CLI overlay left to right. Only the fields you set override lower layers, and network policy always replaces as one unit. The Rust SDK exposes the same model through `SandboxBuilder::overlay` with generated patch types. The generated types replace the earlier handwritten patch types, and `LocalConfig` remains a deprecated alias for `GlobalConfig`. See [Merge precedence](/operations/configuration#merge-precedence) and [`SandboxBuilder::overlay`](/sdk/rust/sandbox#sandbox-overlay). **Other features** * **Go SDK honors `MSB_HOME`.** The Go SDK now resolves its install directory from `$MSB_HOME` when set, matching how the runtime resolves state, sandboxes, and cache. One environment variable now relocates a Go application's entire microsandbox footprint. This makes side-by-side isolated instances possible. ## Bug fixes * Single-file mounts (`--mount-file`) are now fully isolated: sibling files in the host directory can no longer appear in the guest, and host and guest changes stay live. Atomically replacing the host file behaves like a normal file swap. Open descriptors keep reading the old file while fresh opens see the replacement. Per-file quotas no longer count unrelated siblings. * Read-only strict bind mounts no longer perform a write probe on the host mount root at startup. Mounting a directory you can read but not write now works with `ro`, and permission diagnostics are clearer. * Hosts that create many short-lived sandboxes no longer run out of network slots. microsandbox recycles slots from removed sandboxes once the internal counter crosses its cap, so `msb create` keeps working instead of aborting. Genuine exhaustion at 65535 simultaneously live sandboxes now surfaces a clear error instead of a crash. * `msb logs` now behaves consistently for local and cloud sandboxes. Follow mode streams cloud output live, bounded cloud-history filters that are not yet supported return a typed error, and the SDKs expose a boot-error diagnostic for local sandboxes. See [Logs](/sandboxes/logs). * The CLI and SDKs now treat an empty `MSB_HOME` value as unset and fall back to `~/.microsandbox` instead of resolving paths against the current working directory. Callers that relied on `MSB_HOME=""` must use an explicit path. # Week of September 4, 2026 Source: https://docs.microsandbox.dev/changelog/2026-09-04 Outbound SOCKS proxies for sandbox traffic, SOCKS5 UDP relay and proxy authentication, and a fix for upgrades from earlier releases. **Released this week:** [v0.6.17](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.17) ## New features **Outbound SOCKS proxies** Sandboxes can now route their outbound TCP traffic through an external SOCKS4 or SOCKS5 proxy, such as mitmproxy. Guest applications connect to their normal destinations; microsandbox forwards eligible connections through the proxy on the host. With your own CA certificates installed in the sandbox, you can log and inspect the traffic. Configure the proxy through the CLI or the Rust, TypeScript, Python, Go, and Ruby SDKs. ```bash theme={null} msb run python --proxy socks5://127.0.0.1:1080 ``` See [Proxy](/networking/outbound-proxy). **SOCKS5 UDP relay and proxy authentication** SOCKS5 proxies now carry non-DNS UDP traffic in addition to TCP. Both proxy types also support authentication. SOCKS4 accepts an optional user ID, and SOCKS5 accepts a username and a password read from a host environment variable. The password stays out of your code and shell history. See [SOCKS4 user ID](/networking/outbound-proxy#socks4-user-id) and [SOCKS5 credentials](/networking/outbound-proxy#socks5-credentials). ## Bug fixes * Upgrading an existing installation from an earlier release works again. microsandbox now preserves the released database migration order, so databases created by v0.6.15 upgrade cleanly. # Week of September 11, 2026 Source: https://docs.microsandbox.dev/changelog/2026-09-11 Strict hostname policy mode for network allowlists, standard stream devices in the guest, and forward-compatible cloud request handling. **Released this week:** [v0.6.18](https://github.com/superradcompany/microsandbox/releases/tag/v0.6.18) ## New features **Strict hostname policy mode** Network policies can now fail closed when a hostname allow rule fires but microsandbox cannot inspect the request authority. In strict mode, hostname-based allows still work for plaintext HTTP and TLS-intercepted HTTPS. Non-intercepted HTTPS is denied when only a hostname rule would have allowed it. IP, CIDR, group, and default allows are unaffected. Strict mode is opt-in and enforced before the outbound TCP connection is dialed. ```bash theme={null} msb create alpine --name restricted-worker \ --net-default-egress deny \ --net-rule "allow@example.com:tcp:443" \ --net-strict ``` See [Hostname rules and HTTPS](/networking/overview#hostname-rules-and-https) and [`--net-strict`](/cli/sandbox-commands). **Other features** * **Forward-compatible cloud requests.** The cloud API now ignores unknown fields in network and runtime settings from newer SDKs while preserving defaults, required-field checks, and validation of recognized values. SDKs and the cloud service can ship on independent release cadences without breaking existing clients. ## Bug fixes * HTTP host policy checks now match the hostname that the policy allowed, closing a gap where a mismatched `Host` header could bypass a hostname-based allow rule. * `/dev/stdin`, `/dev/stdout`, and `/dev/stderr` are now created during guest initialization alongside `/dev/fd`. Commands such as `printf 'echo hello\n' | bash /dev/stdin` work inside sandboxes, and existing entries are preserved when initialization runs again. # Week of September 25, 2026 Source: https://docs.microsandbox.dev/changelog/2026-09-25 v0.7.3 fixes for saved sandbox configuration and macOS runtime discovery, plus snapshot upgrade guidance. **Released this week:** [v0.7.3](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.3) ## Fixes * **Existing sandbox configuration.** v0.7.3 migrates saved v0.6 secret policies, including Basic Auth and query substitution settings, so existing sandboxes can load without being deleted and recreated. * **macOS runtime discovery.** Starting microsandbox through a symlink now finds the matching `libkrunfw` library in the installation directory. ## Upgrading snapshot code from v0.6 Local snapshot groups introduced in v0.7 have immutable members. This behavior also applies in v0.7.3. SDK calls with `force=True` fail even when no snapshot exists under the requested name. Code that previously overwrote a named snapshot must change: ```python Before: v0.6 theme={null} from microsandbox import Snapshot snapshot = await Snapshot.create( "checkpoint", from_sandbox="workbench", force=True ) ``` Omit the name to generate a new member for each capture, and leave `force` at its default of `False`: ```python After: v0.7 theme={null} from microsandbox import Snapshot snapshot = await Snapshot.create(from_sandbox="workbench") ``` You can also supply a unique member name. If you need to reuse an existing name, explicitly remove that member first using [`Snapshot.remove()`](/sdk/python/snapshots#snapshot-remove). Removal still checks for dependent snapshots, and deleting a member does not preserve it if the next capture fails. This restriction applies to installed group members. Direct archive capture can overwrite its output file. See [snapshot groups](/sandboxes/snapshots#snapshot-groups) and the [Python snapshot reference](/sdk/python/snapshots). # v0.7.0 Source: https://docs.microsandbox.dev/changelog/v0.7.0 Save running sandboxes, branch them into independent copies, and resume work from a checkpoint. September 16, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.0) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.6.18...v0.7.0) Release entries start here. Earlier updates remain in the weekly archive. ## Snapshots and branching **Save running work.** Full snapshots capture a local sandbox's disk, memory, and running processes so you can resume from a checkpoint: ```bash theme={null} msb create alpine --name app --memory 512M msb exec app -- sh -c 'echo ready > /dev/shm/message' msb snapshot create ready --from-sandbox app --full msb restore app:ready --name restored msb exec restored -- cat /dev/shm/message # ready ``` **Try several paths from one starting point.** Branch a running or paused sandbox into independent copies, including several children at once. Copies share unchanged memory while keeping their writes private. You can also pause and resume a sandbox without saving a snapshot. **Organize and move checkpoints.** Snapshot groups, portable `.msb` archives, and incremental exports make saved work easier to manage. Disk-only snapshots now support running and paused local sandboxes; the SDK also adds cloud disk snapshots and restore through a compatible service. Full snapshots, branching, groups, and archives are local-only. See [Snapshots](/sandboxes/snapshots) for commands and requirements. ## More features * **Storage that follows your sandbox.** Owned volumes survive restarts and become private copies in snapshots and branches. Root disks can grow without restarting, sealed layers can be compacted, and flat roots gain snapshot and pre-boot patch support. [Volumes](/sandboxes/volumes) · [Disk maintenance](/sandboxes/snapshots#export-changes-and-compact-a-disk-chain) * **More precise secret policies.** Control where credentials are substituted, where placeholders may pass unchanged, and how violations are handled. Real credentials stay on the host. [Secrets](/sandboxes/secrets) * **Network controls and diagnostics.** Set TCP and UDP connection limits independently, and trace startup and connection timings with optional profiling. ## Improvements and fixes * New `msb sandbox` and `msb sbx` command groups retain familiar top-level commands. * Faster agent I/O through separate control and bulk-data paths, with shared-memory transport for supported local Unix SDK connections. * Disk-backed temporary storage and faster reclamation of completed TCP connections. * Stale handles can no longer reach a replacement sandbox with the same name. * Fixed macOS bind-mount truncation and TLS hostname panics; added standard stream paths and support for older metrics registries. * Cloud requests tolerate unknown network and runtime fields while validating known settings. New settings still require server support. ## Before upgrading Moving from v0.6? Follow the [v0.7 migration guide](/migrations/v0.7), targeting v0.7.3 or a later compatible patch release. * **Set up the runtime first.** Sandbox creation no longer downloads it automatically. SDK setup APIs and Rust build features have changed. [Runtime setup](/sdk/setup) * **Migrate secret policies.** v0.7.3 migrates saved policies automatically; application code and configuration files may need changes. See [secret policy migration](/migrations/v0.7#review-secret-policies). * **Reconnect external resources.** Restore and branch need explicit host mounts, published ports, and custom vsock routes. Snapshots do not copy host files or restore external connections. Use compatible runtime and firmware versions. * **Choose shutdown timeouts.** Graceful stop has no default deadline. A timeout does not force-kill the sandbox; killing requires an explicit request. * **Review network limits.** Defaults are unlimited for single-tenant sandboxes and 1,024 each for TCP and UDP in multi-tenant sandboxes. Zero means unlimited. `maxConnections` remains a deprecated TCP-only alias. ## New guides Get started with [Browser Use](/examples/browser-automation/browser-use) or [VS Code](/examples/development/vscode). The API reference now also covers personal tokens. ## Contributors Thank you to everyone who contributed to this release. # v0.7.1 Source: https://docs.microsandbox.dev/changelog/v0.7.1 Choose how snapshots save pending disk writes, with fixes for upgrades and Node package installation. September 17, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.1) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.0...v0.7.1) ## Control snapshot disk writes The new `--guest-flush` option controls whether pending filesystem writes reach disk before snapshots, branches, or pause. All four SDKs support it. * **`auto` (default):** Flushes running disk-only snapshots. Full snapshots, branches, and pause retain pending writes in memory without an extra flush. * **`required`:** Requires a flush, useful when restoring a full snapshot's disks without its memory. * **`skip`:** Skips the optional flush. Disk-only snapshots may miss recent writes and need filesystem recovery. ```bash theme={null} msb snapshot create full --from-sandbox worker --full --guest-flush required ``` This covers root and captured owned disks. Applications must still save their own buffered data. See [Guest flushing](/sandboxes/snapshots#guest-flushing). ## Fixes * Fixed sandbox creation after upgrading from v0.6.18 to v0.7.0. * Fixed older runtime launch requests; unsupported settings are rejected before replacing a sandbox. * Included missing Node native type declarations. * Made npm publication resumable, ordered dependencies correctly, and added SDK provenance information. ## Before upgrading Moving from v0.6? Follow the [v0.7 migration guide](/migrations/v0.7), targeting v0.7.3 or a later compatible patch release. * Owned disks no longer trigger automatic flushing for full snapshots, branches, or pause. Use `required` if you depend on it. * Paused sandboxes need a prior flush when capture requires one. `required` fails for stopped or crashed sandboxes. * Restart older runtimes before live disk capture. Go needs a policy-aware native library; Rust callers constructing `SnapshotSpec` must add `guest_flush`. * Catalog upgrades still require stopping running sandboxes in this version. [v0.7.2](/changelog/v0.7.2) removes that restriction. ## Contributors Thank you to everyone who contributed to this release. # v0.7.2 Source: https://docs.microsandbox.dev/changelog/v0.7.2 Upgrade your local sandbox database without stopping running sandboxes. September 17, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.2) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.1...v0.7.2) ## Upgrade without stopping sandboxes The CLI and SDKs can now upgrade supported older local sandbox databases while existing sandboxes keep running. This removes v0.7.1's stop requirement while preserving database locking and rollback safeguards. The release also fixes loading older saved configurations, including v0.6.5 formats, and checks runtime compatibility before replacing a sandbox. ## Before upgrading Moving from v0.6? Follow the [v0.7 migration guide](/migrations/v0.7), targeting v0.7.3 or a later compatible patch release. Running VMs can keep their existing runtime, but older SDKs and CLIs may refuse to open the upgraded database. Selecting an older runtime does not downgrade the database. ## Contributors Thank you to everyone who contributed to this release. # v0.7.3 Source: https://docs.microsandbox.dev/changelog/v0.7.3 Enforce team settings, work with simpler snapshot commands, and wait for sandboxes in scripts. September 24, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.3) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.2...v0.7.3) ## New features **Enforce team settings.** A protected `managed.json` takes priority over user configuration, CLI flags, and SDK options across local and cloud backends. Unix installs reject unsafe file or parent-directory permissions. [Managed deployment](/enterprise/managed-configuration) **Simpler snapshot commands.** Capture, restore, export, and import now fit under `msb snap`: ```bash theme={null} msb snap create ready --sandbox app msb snap restore app:ready --name worker msb snap export app:ready --output ready.msb msb snap import ready.msb ``` Older forms still work. You can also name snapshots with `--name` and filter with `msb snap ls --group GROUP`. [Snapshots](/sandboxes/snapshots) **Wait in scripts.** `msb wait worker --timeout 5m --format json` waits for a sandbox to stop or crash. It does not stop the sandbox or confirm workload success. [Command reference](/cli/sandbox-commands#msb-wait) ## Before upgrading Moving from v0.6? Follow the [v0.7 migration guide](/migrations/v0.7), targeting v0.7.3 or a later compatible patch release. * **HTTPS hostname rules need inspection.** Strict hostname checking is now on by default. HTTPS allowed only by hostname needs TLS interception or is blocked. IP, CIDR, group, and default allow rules are unaffected. Opt out with `--net-strict=false` or `network.strict: false`; Go replaces `Strict` with `DisableStrict`. [Hostname rules](/networking/overview#hostname-rules-and-https) * **Rust configuration APIs changed.** `LocalBackend::lazy()` and `LocalBackendBuilder::build_lazy()` return `Result`. `SdkConfig` and `load_sdk_config()` are removed. [Migration details](/migrations/v0.7#review-other-application-changes) * **Check shared database access.** Stop incompatible SDK processes sharing `MSB_HOME` before upgrading. Running VMs are handled separately. Cloud services need a separate update for older configuration formats. ## Fixes * Preserved v0.6 secret passthrough settings and support for older snapshots and custom filenames. Unsupported settings and incompatible downgrades fail before changes are made. * Secret updates enable TLS interception when needed and, by default, report required restarts before saving. * Reduced delays for server-first protocols. Binary traffic avoids HTTP secret substitution while retaining blocked-placeholder checks. * Fixed firmware lookup through macOS command links, cleanup of unresponsive guests, musl detection, and Linux network builds. ## New guides Added [corporate networking](/enterprise/corporate-networking), [offline deployment](/enterprise/prepare-environment#prepare-offline-devices), and dedicated CLI references for [snapshots](/cli/snapshot-commands), [registries](/cli/registry-commands), and [management](/cli/management). ## Contributors Thank you to everyone who contributed to this release. # v0.7.4 Source: https://docs.microsandbox.dev/changelog/v0.7.4 More reliable secret scanning, writable macOS hard links, and typed Ruby errors. September 25, 2026 · [GitHub tag](https://github.com/superradcompany/microsandbox/tree/v0.7.4) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.3...v0.7.4) ## Fixes * **Secret scanning respects request locations.** Valid requests with percent or Unicode escapes in their bodies no longer fail because of an allowed header placeholder. The fix covers HTTP/1 and HTTP/2 and retains checks for forbidden placeholders. Secrets are not substituted into trailers. * **macOS hard links remain writable.** Removing one filename no longer prevents writes through surviving hard links. Open handles retain permitted access after the final link is removed, with host permission checks preserved. * **Ruby standalone builds use the correct dependency pin.** Refreshed the standalone Cargo lockfile and added a registry-pin check. * **Rust publication respects development dependencies.** Versioned development dependencies are published before crates that require them. ## SDK changes **Clearer placeholder permissions.** Prefer `allow_placeholder_for` in Rust and Python, `allowPlaceholderFor` in TypeScript, and `AllowPlaceholderFor` in Go. The previous passthrough-named APIs remain as deprecated aliases. Policy behavior, CLI options, and stored fields are unchanged. **Typed Ruby errors.** Core failures now raise specific subclasses of `Microsandbox::Error`, with stable `code` values. Existing `rescue Microsandbox::Error` handlers continue to work. Argument validation still raises `ArgumentError` or `TypeError`. ## Upgrading from v0.6 Follow the [v0.7 migration guide](/migrations/v0.7). This patch adds fixes to the compatibility work shipped in v0.7.3. ## Contributors Thank you to everyone who contributed to this release. # v0.7.5 Source: https://docs.microsandbox.dev/changelog/v0.7.5 Fork running sandboxes with clearer commands, run scripted commands without stdin, and opt in to readable network denials. September 30, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.5) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.4...v0.7.5) ## New features **Fork running sandboxes.** Live duplication is now called forking, and branching refers only to paths through snapshot history. Full restores use explicit copy-on-write memory names: ```bash theme={null} msb fork worker --name experiment msb fork worker --names alice bob msb snap restore worker:ready --name restored --cow-mem ``` The SDKs add `fork` and `forkMany` in TypeScript, `fork` and `fork_many` in Rust and Python, and `Fork` and `ForkMany` in Go. Forking remains local-only. [Forking](/sandboxes/snapshots#forking) **Leave host input alone.** `msb exec --no-stdin` and `msb run --no-stdin` give the guest command immediate EOF without consuming the calling script's input. Combine it with `--stream` for live output. It conflicts with `--tty`. [Command reference](/cli/sandbox-commands#msb-exec) **Readable network denials.** Set `http.deny_response: true` to answer default-denied HTTP and intercepted HTTPS requests with a `403 Forbidden` instead of a dropped connection. `deny_message` customizes the body, so you can tell an agent how to request access. [Denied requests](/networking/overview#what-a-denied-http-request-sees) **Tune published-port queues.** `--tcp-accept-queue-size` sets how many pending connections each published TCP port can hold, from `1` to `2147483647`. [Published ports](/cli/sandbox-commands#published-ports) ## Before upgrading * **Rename branch and forked calls.** `msb branch`, the branch SDK methods, `--forked`, `.forked()`, `forked=`, and `WithForked` remain as deprecated aliases. Prefer `msb fork`, the fork methods, `--cow-mem`, `.cowMemory()`, `cow_memory=`, and `WithCowMemory`. The CLI, Node, and Python report deprecation at runtime. [Migrating restore options](/sandboxes/snapshots#migrating-restore-options) * **Published ports queue more connections.** The default accept queue is now 1,024 instead of 128. Setting a custom size requires a supporting local runtime, and cloud rejects it. * **Denial responses are opt-in.** Connection failures remain the default. Enabling `deny_response` requires a supporting local runtime, and cloud rejects it. A custom message alone does not enable responses. ## Fixes * Piped `msb exec` no longer hangs while the host keeps stdin open. * Hosts allowed to receive a secret may now carry its placeholder unchanged outside substitution locations. Requests that previously blocked or terminated the sandbox now succeed. * Published ports now forward guest connection closes, so host clients see EOF instead of waiting for a timeout. * Public-only policies now classify destinations in NAT64 prefixes by their embedded IPv4 address. Add routed prefixes with `--net-nat64-prefix`. [Security model](/security/network) * Patch parent directories keep the image's owner, mode, and extended attributes. Directories removed by a patch stay removed when a later patch recreates them. * Rejected snapshot and patch combinations no longer leave a directory that blocks retries under the same name. ## Contributors Thank you to everyone who contributed to this release. # v0.7.6 Source: https://docs.microsandbox.dev/changelog/v0.7.6 Host paths stay fixed after a sandbox is created, and local volume operations stay inside the volume. October 1, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.6) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.5...v0.7.6) ## Security hardening **Host paths no longer move.** New local sandboxes save relative host paths from CLI flags and SDK calls as absolute paths when the sandbox is created. Starting the sandbox from another directory keeps the same mount sources and TLS certificate files. Paths in a sandbox configuration file still resolve from that file's directory. Existing saved sandboxes keep their previous behavior and are not rewritten. [Bind mounts](/sandboxes/volumes#bind-mounts) **Local volume access stays confined.** Volume filesystem operations pin the volume directory, so replacing the root path cannot redirect an operation already in progress. Symlinks that resolve inside the volume still work. Paths that escape it return an error. [Go volume paths](/sdk/go/volumes#local-filesystem-paths) **Backends capture their locations.** A local backend fixes its home, path overrides, runtime paths, and registry CA path when you construct it. Later changes to the working directory or `MSB_HOME` do not move its files. Relative snapshot artifact paths resolve when each operation begins. ## Before upgrading * **Check relative paths in configuration files.** Relative host paths in global `config.json` and managed configuration now resolve from the file's own directory, not your working directory. This covers `home`, `paths.*`, and `registries.ca_certs`. Use absolute paths to keep a location elsewhere. [Configuration](/configuration) * **Update the Go native library.** Go local volume operations require the v0.7.6 native SDK library. Older libraries return an unsupported-operation error. * **Fix ambiguous Go paths.** Go no longer cleans `..` before lookup. A path where a symlink followed by `..` would select a different file now returns an error. Name the destination directly. ## Fixes * Metrics readers find runs recorded under both the original and normalized spelling of the home path. Running sandboxes do not need a restart. [Metrics upgrades](/sandboxes/metrics#upgrading-with-running-sandboxes) ## Contributors Thank you to everyone who contributed to this release. # v0.7.7 Source: https://docs.microsandbox.dev/changelog/v0.7.7 Connect through HTTP proxies, inspect local storage, and control the clock in snapshot-based tests. October 5, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.7) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.6...v0.7.7) ## New features **Use an HTTP CONNECT proxy.** Local sandboxes can tunnel outbound TCP through an HTTP proxy, alongside existing SOCKS support. Destination policies still apply. Proxy authentication, UDP, DNS forwarding, and host image downloads are not covered by this tunnel. ```bash theme={null} msb create alpine --name proxied --proxy http://127.0.0.1:3128 ``` See [proxy setup and limits](/networking/outbound-proxy#http-connect). **See what uses disk space.** `msb df` reports local storage usage; `msb prune --dry-run` previews unused runtime memory files that can be removed. Pruning preserves saved snapshots, sandbox disks, volumes, and images. The SDKs expose storage reporting and cleanup too. [Storage commands](/cli/storage-commands) **Keep a snapshot's starting time.** `--guest-clock off` stops host clock updates after boot, so full restores continue from saved time. The guest clock still advances. Available through the local CLI and Rust SDK. [Guest clock](/sandboxes/snapshots#keep-the-guest-clock) The bundled guest kernel is updated to Linux 6.12.111. Other additions include command-tree display controls and direct file-memory mapping support (DAX) in Linux and Windows filesystem backends. macOS DAX is not included. ## Fixes * Paused sandboxes use less host CPU; host-resident memory metrics are unavailable while paused rather than reporting stale values. * TCP responses drain before closing, ports work without host routes, and rotating DNS answers retain earlier addresses until expiry. * Snapshot archives import across disk locations and reordered metadata; restored CPU and memory targets are available during startup. * Non-root commands receive resource limits correctly. SFTP creates files as the session user, and startup errors expose guest initialization failures. Symlinked bind-mount roots fail early with a useful error. * SDK fixes protect secret handling, preserve Go binary output, and support Python secret-policy updates. Sandboxes that never started can be removed. ## Before upgrading * **Ruby now requires 3.3 or newer.** Update Go's native library for configured-shell execution and binary-output fixes. * **Check numeric inputs.** TypeScript rejects invalid or out-of-range numeric options. Python lifetime values must be finite and non-negative. * **Upgrade snapshot readers together.** New Windows full snapshots preserve bind-mount hardlinks and require an updated runtime to restore. * **Plan clock-policy rollback.** Older tools cannot read full snapshots saved with the clock set to `off`. Downgrading the local database is blocked while saved or active sandboxes use that policy. See the [upgrade guide](/migrations/v0.7#later-v0-7-releases) for patch-release compatibility notes. ## Contributors Thank you to everyone who contributed to this release. # v0.7.8 Source: https://docs.microsandbox.dev/changelog/v0.7.8 Keep commands running after disconnecting, narrow secret substitution, and restore snapshots with explicit storage bindings. October 9, 2026 · [GitHub release](https://github.com/superradcompany/microsandbox/releases/tag/v0.7.8) · [All changes](https://github.com/superradcompany/microsandbox/compare/v0.7.7...v0.7.8) ## New features **Leave a command running and return later.** Detached jobs belong to the local sandbox runtime, so closing the launching terminal does not stop them. Inspect their status, follow logs, attach, or wait from another client. The SDKs expose the same job controls. ```bash theme={null} msb create alpine --name worker job=$(msb exec -d --no-stdin worker -- sh -c 'echo started; sleep 60; echo done') msb logs worker --job "$job" --follow msb wait worker --job "$job" ``` Stopping the sandbox still stops its jobs. A restart does not rerun them. [Managed jobs](/sandboxes/commands#managed-jobs) **Send secrets only in intended headers.** Restrict substitution with `headers=[authorization]` on the CLI or `substitution.header_fields` in configuration. This reduces the risk of an allowed endpoint echoing a credential from an unrelated header. Existing policies still substitute in all headers unless narrowed. [Secret policies](/sandboxes/secrets) **Configure application certificate trust.** The optional `msb-trust.sh` helper configures supported applications to trust the sandbox's TLS interception CA. Run it explicitly after boot. [Application trust](/networking/tls#application-trust) **Publish port ranges and rebind disks.** Equal-length ranges such as `-p 8000-8002:80-82` expand into individual listeners. Restore and fork accept `--mount-disk` to rebind captured disks. Full restores and forks cannot add a new disk device. [Ports](/cli/sandbox-commands#published-ports) · [Snapshot mounts](/sandboxes/snapshots#external-mounts) **Capture larger filesystem state.** `snapshots.max_filesystem_state_mib` sets the per-device budget for full snapshots and forks, defaulting to 4 MiB. [Configuration](/configuration#snapshots) ## Before upgrading * **Map external mounts on disk restores.** Restores now reject missing recorded host mounts. Supply bindings or explicitly accept missing resources with `--allow-missing-resources`. Older disk snapshots without mount records behave as before. * **Finish active jobs before full snapshots or forks.** Resident pause/resume remains supported. * **Update the runtime for new capabilities.** Scoped secret headers and non-default filesystem budgets require support. Snapshot readers need sufficient budgets; older releases may reject larger state. See [upgrade notes](/migrations/v0.7#later-v0-7-releases). ## Fixes Disk-only restores work directly from archives. Cleanup and snapshot recovery are more reliable, including on Windows, where directory renames also keep cached paths current. Linux catalog checks preserve SQLite locks, memory metrics follow live resizing, malformed HTTP/2 headers are rejected safely, and client disconnects no longer stop the shared relay. ## Contributors Thank you to everyone who contributed to this release. # Configuration Source: https://docs.microsandbox.dev/cli/configuration Configure sandbox resources, networking, and storage with reusable microsandbox CLI YAML files. Load reusable sandbox settings with `--conf`. See [configuration precedence](/operations/configuration#precedence) for global defaults. Common image, resource, lifecycle, environment, policy, secret, script, and patch fields work everywhere. Host-integrated networking, local rootfs forms, snapshots, replace behavior, and several runtime fields are unavailable on microsandbox cloud. Files may have any name and contain only the fields you need. Explicit CLI arguments override their values. ```yaml theme={null} # sandbox.yaml image: "python:3.12" cpus: 2 memory: "1G" workdir: "/app" mounts: - "./src:/app" network: allow: ["api.openai.com"] ports: ["8000:8000"] secret_violation_action: block-and-log secrets: OPENAI_API_KEY: allow: ["api.openai.com"] substitution: headers: true query: false body: false passthrough: ["telemetry.example.com"] scripts: start: "python app.py" ``` ```bash theme={null} msb run --conf sandbox.yaml -- start msb create --conf sandbox.yaml --name agent msb install --conf sandbox.yaml --name agent ``` Files are never auto-discovered; pass each file explicitly. ## Sparse configuration Required fields are checked after merging files and CLI arguments. For example, supply the image separately from a network-only file: ```yaml theme={null} # net-policy.yaml network: policy: public allow: - "api.openai.com" deny: - "169.254.169.254" ``` ```bash theme={null} msb run python --conf net-policy.yaml ``` If neither the files nor the arguments provide an image, the command fails before pulling an image or creating sandbox state. ## Scoped config files Scoped files contain one group of settings without its wrapper key. Unrelated fields are rejected. | Flag | Accepted fields | | - | - | | `--conf PATH` | Any sandbox configuration field | | `--net-conf PATH` | `policy`, `allow`, `deny`, `ports`, `dns`, `tls`, `strict`, `trust_host_cas`, `max_tcp_connections`, `max_udp_connections`, `tcp_accept_queue_size` | | `--resource-conf PATH` | `cpus`, `memory`, `max_duration`, `idle_timeout`, `rlimits` | | `--runtime-conf PATH` | `workdir`, `shell`, `user`, `hostname`, `security`, `entrypoint`, `cmd`, `env`, `labels`, `init` | | `--fs-conf PATH` | `mounts`, `patch_files`, `patches` | | `--secret-conf PATH` | A map of secret names to secret definitions | | `--script-conf PATH` | A map of script names to shell snippets | For example, `--net-conf` expects this unwrapped document: ```yaml theme={null} policy: public allow: - "api.openai.com" deny: - "169.254.169.254" ``` ```bash theme={null} msb run python --net-conf net-policy.yaml ``` Passing `network: {...}` to `--net-conf` is an error; use `--conf` for a root-shaped document. ## Combining files Root and scoped configuration flags are repeatable and may be interleaved. The CLI applies each file from left to right, then applies explicit flags and positional arguments. See [Precedence](/operations/configuration#precedence) and [Merge precedence](/operations/configuration#merge-precedence) for the complete resolution rules. `--net-conf` cannot be combined with `--net`, `--no-net`, `--net-rule`, or `--net-default*`. When network policy is loaded through a root `--conf` file instead, a policy CLI flag replaces it, while `--net-rule` remains additive and is evaluated before rules loaded from the file. ```bash theme={null} # Files overlay left to right; --memory wins unless managed policy overrides it. msb run python \ --conf base.yaml \ --resource-conf standard.yaml \ --conf project.yaml \ --resource-conf large.yaml \ --memory 12G ``` Relative host paths are resolved against the file that contains them. Paths inside a file listed by `patch_files` are resolved against that patch file. Rust applications can apply the same sparse configuration model without loading YAML. See [`SandboxBuilder::overlay`](/sdk/rust/sandbox#sandbox-overlay) for the typed API, merge behavior, and migration from the earlier patch types. ## Schema ### Image and registry The common image form is a string. Local paths beginning with `.`, `..`, or `/` are resolved as bind roots or disk images; other strings are OCI references. ```yaml theme={null} image: "python:3.12" pull_policy: missing # missing | always | never registry: username: "deploy" password_env: "REGISTRY_TOKEN" ``` Use the object form to select a source explicitly: ```yaml theme={null} image: { oci: "python:3.12", upper_size: "8G" } image: { snapshot: "prepared-agent" } image: { disk: "./ubuntu.qcow2", fstype: ext4 } image: { bind: "./rootfs" } ``` Exactly one source is allowed. Project layer references are not valid in single-sandbox configuration; consume a published layer as an OCI reference instead. ### Resources and lifecycle ```yaml theme={null} cpus: 2 memory: "1G" max_duration: "12h" idle_timeout: "10m" rlimits: - { resource: nofile, soft: 8192, hard: 16384 } - { resource: nproc, soft: 512 } ``` When `hard` is omitted it equals `soft`. ### Runtime ```yaml theme={null} workdir: "/app" shell: "/bin/bash" user: "app" hostname: "api" security: restricted # default | restricted entrypoint: ["/usr/bin/tini", "--"] cmd: ["python", "app.py"] env: MODE: "production" labels: team: "platform" init: cmd: auto # auto or an absolute guest path args: [] env: {} ``` `cmd` is the default workload for `msb run`. `msb create` stores it without launching it. ### Mounts A string mount is a config-relative bind mount using the same `SOURCE:TARGET[:OPTIONS]` option grammar as a bind passed to `-v/--volume`. Options include `ro`, `rw`, `noexec`, `nosuid`, `nodev`, `follow-root-symlinks`, `stat-virt=strict|relaxed|off`, `host-perms=private|mirror`, `quota=`, and paired `uid=,gid=`: ```yaml theme={null} mounts: - "./src:/app" - "./certs:/etc/app/certs:ro,noexec" - "./workspace:/workspace:uid=1000,gid=1000" ``` Object mounts require exactly one source and a guest `target`: ```yaml theme={null} mounts: - bind: "./src" target: "/app" stat_virtualization: strict host_permissions: private uid: 1000 gid: 1000 - named: cache target: "/var/cache/app" create: ensure-exists - tmpfs: { size: "256M" } target: "/run" noexec: true - disk: "./seed.qcow2" target: "/seed" format: qcow2 fstype: ext4 readonly: true ``` All mount kinds accept `readonly`, `noexec`, `nosuid`, and `nodev`. `stat_virtualization`, `host_permissions`, and paired `uid`/`gid` apply only to bind and directory-backed named mounts. Ownership changes only the guest fallback for files without a per-file stat override; it does not change host inode ownership. Duplicate guest targets are rejected. ### Rootfs patches Patch files run first in listed order, followed by inline patches: ```yaml theme={null} patch_files: - "./patches/common.yaml" patches: - copy_file: { src: "./config.toml", dst: "/etc/app/config.toml", mode: "0644", replace: true } - copy_dir: { src: "./certs", dst: "/etc/app/certs" } - text: { path: "/etc/app/build.txt", content: "release", mode: "0644" } - file: { path: "/etc/app/blob.bin", content_base64: "SGVsbG8=", mode: "0600" } - mkdir: { path: "/var/cache/app", mode: "0755" } - symlink: { target: "/etc/app/config.toml", link: "/etc/app/active.toml" } - append: { path: "/etc/hosts", content: "10.0.0.5 db.internal\n" } - remove: { path: "/etc/motd" } ``` A patch file has one top-level `patches` list using the same operations. File modes must be quoted four-digit octal strings. ### Network Use a preset string for the common cases: ```yaml theme={null} network: public # none | public | open ``` `public`, the default, permits public internet access while blocking private, loopback, link-local, and metadata destinations. `none` denies ingress and egress. `open` is unrestricted. The object form adds rules and network services: ```yaml theme={null} network: policy: public allow: ["api.openai.com", "*.stripe.com"] deny: ["169.254.169.254"] ports: ["8000:8000", "9100:9100/udp"] dns: rebind_protection: true nameservers: ["1.1.1.1", "8.8.8.8"] query_timeout: "5s" tls: enabled: true bypass: ["*.internal.example"] verify_upstream: true block_quic: true strict: true trust_host_cas: false max_tcp_connections: 256 ``` A non-empty `allow` list implies deny-by-default egress. `strict` defaults to `true` and requires hostname-based allow rules to use an inspectable request authority. Plain HTTP exposes that authority in `Host`; HTTPS only exposes it when TLS interception is enabled and not bypassed. Without that visibility, strict mode denies HTTPS that would otherwise be allowed only by a hostname rule. Set `strict: false` to opt out. Top-level `ports` is shorthand for `network.ports`; when both are present, the lists are combined and duplicate host ports are rejected. Both `ports` lists accept inclusive, equal-length host and guest ranges, including bind addresses and `/tcp` or `/udp`: ```yaml theme={null} network: policy: open ports: - "0.0.0.0:10240-11264:10240-11264/udp" - "8000-8002:80-82" ``` Ranges pair ports in ascending order and expand into individual mappings before launch. Endpoints must be from 1 to 65535; reversed, malformed, out-of-bounds, and unequal-length ranges are rejected. The first entry opens 1,025 host sockets, so provision host socket/file-descriptor capacity accordingly. See [Published ports](/cli/sandbox-commands#published-ports) for bind addresses and resource considerations. ### Secrets Every secret requires a non-empty destination allowlist. When `value` is omitted, the host environment variable with the same name is used. An exact `${NAME}` value records `NAME` as the host-side source instead of copying its plaintext into durable config. ```yaml theme={null} secrets: OPENAI_API_KEY: allow: ["api.openai.com"] DATABASE_URL: value: "${DB_DSN}" allow: ["db.internal"] substitution: headers: false query: false body: true passthrough: ["audit.internal"] violation_action: block-and-terminate require_tls_identity: true ``` `substitution` controls headers, query parameters, and request bodies independently; it defaults to headers only, and Basic authentication follows the header setting. On credential-allowed hosts that pass the secret's identity checks, disabled locations forward the placeholder unchanged. Other destinations must appear in `passthrough` or follow the violation action. `secret_violation_action` sets the sandbox-wide blocking action, while a per-secret `violation_action` overrides it. Declaring a secret enables TLS interception and DNS-rebind protection. ### Scripts Scripts are named shell snippets installed as executables in `/.msb/scripts`, which is on `PATH`. The sandbox configuration's `shell` selects their shebang and defaults to `/bin/sh`. ```yaml theme={null} shell: "/bin/bash" scripts: start: "python app.py" migrate: "alembic upgrade head" ``` Run a script like any other guest command: ```bash theme={null} msb run --conf sandbox.yaml -- migrate ``` ## Validation Sandbox configuration is data, not a templating language. The loader rejects unknown fields, duplicate keys, multiple YAML documents, anchors, aliases, merge keys, and custom tags. Bare YAML 1.1 booleans such as `yes`, `no`, `on`, and `off` are rejected. Quote modes, sizes, durations, ports, domains, image references, and other typed strings. Only `${NAME}` environment substitution is supported. Substituted variables must exist when the config is loaded; an exact secret `value: "${NAME}"` is the exception because it records a host-side source that is resolved when the sandbox starts. Shell-style operators such as `${NAME:-fallback}`, includes, templates, loops, and expressions are not supported. Project envelope fields such as `sandboxes`, `volumes`, and `layers`, plus per-project fields such as `depends_on`, are rejected in single-sandbox configuration. ### UDP session limit Set `max_udp_connections` in the network configuration, or pass `--max-udp-connections 512`. The default is unlimited in single-tenant mode and 1,024 relay sessions in multi-tenant mode; zero explicitly selects unlimited. At capacity, new sessions evict the least recently active session. `max_connections` and `--max-connections` remain deprecated TCP-only aliases for `max_tcp_connections` and `--max-tcp-connections`. Specifying both TCP names in one configuration or command is an error. The UDP limit is independent. ### Published-port accept queue size Set `tcp_accept_queue_size` in the network configuration, or pass `--tcp-accept-queue-size 4096`, to change how many not-yet-accepted connections each published TCP port queues on the host. The default is 1,024, and values from 1 to 2,147,483,647 are accepted; the host kernel caps the effective depth at its own `somaxconn`. See [Published ports](/cli/sandbox-commands#published-ports). # Image commands Source: https://docs.microsandbox.dev/cli/image-commands Pull, inspect, and manage cached OCI images with the microsandbox CLI. Local-only ## msb pull Download an image to the local cache. Shared layers are stored once. ```bash theme={null} msb pull python msb pull alpine msb pull ghcr.io/my-org/my-image:v1 msb pull python --materialize flat msb pull python --materialize all ``` Expanded form: `msb image pull`. | Flag | Description | | - | - | | `-f`, `--force` | Force re-download even if cached | | `-q`, `--quiet` | Suppress progress output | | `--insecure` | Connect over plain HTTP instead of HTTPS | | `--ca-certs ` | Path to a PEM file with additional CA root certificates | | `--materialize ` | Explicitly prepare `layered`, `flat`, or `all` rootfs artifacts | [Managed registry settings](/configuration#auth-resolution-order) take precedence over `--insecure`, `--ca-certs`, and supplied credentials. A managed TLS-only entry preserves normal credential lookup. `layered` prepares the standard root; `flat` prepares a complete ext4 base; `all` prepares both. See [flat roots](/cli/sandbox-commands#flat-oci-rootfs). Without `--materialize`, the configured `sandbox_defaults.oci.root_disk` selects the layout. The built-in default is layered. Pre-pulling is useful when you want sandbox creation to be instant. Without a pre-pull, the first `Sandbox.create` with a new image will block on the download. ## msb load Load a Docker image archive or OCI Image Layout archive into the local microsandbox cache. References are installed and recorded individually; if a later reference fails, earlier completed references remain installed. A cache eviction during a warm import is recovered from the supplied archive. ```bash theme={null} docker save my-image:latest | msb load msb load --input my-image.tar msb load --input oci-layout.tar --tag my-image:latest ``` Expanded form: `msb image load`. | Flag | Description | | - | - | | `-i`, `--input ` | Read archive from a tar file instead of stdin | | `-t`, `--tag ` | Add a local image reference to the first imported image | | `-q`, `--quiet` | Suppress output | ## msb save Save one or more cached images as a Docker-compatible archive or OCI Image Layout archive. ```bash theme={null} msb save --output my-image.tar my-image:latest msb save --format oci --output my-image.oci.tar my-image:latest msb save my-image:latest > my-image.tar ``` Expanded form: `msb image save`. | Flag | Description | | - | - | | `--format ` | Archive format (`docker`, `oci`; default: `docker`) | | `-o`, `--output ` | Write archive to a tar file instead of stdout | | `-q`, `--quiet` | Suppress output | Exports preserve image contents, but regenerated layers can change image and layer digests. ## msb images List images in the local cache. ```bash theme={null} msb images msb images --format json msb images -q # References only ``` Expanded form: `msb image ls`. | Flag | Description | | - | - | | `--format` | Output format (`json`) | | `-q`, `--quiet` | Show only image references | ## msb image inspect Show detailed metadata for a cached image (manifest, layers, config). ```bash theme={null} msb image inspect python msb image inspect python --format json ``` | Flag | Description | | - | - | | `--format` | Output format (`json`) | ## msb rmi Remove one or more cached images and their layers (layers shared with other images are kept). ```bash theme={null} msb rmi python msb rmi alpine ubuntu # Remove multiple ``` Expanded form: `msb image rm`. | Flag | Description | | - | - | | `-f`, `--force` | Remove the image reference while preserving backing needed by sandboxes or snapshots | | `-q`, `--quiet` | Suppress output | ## msb image prune Remove cached images that are not used by any sandbox or indexed snapshot, then clean up dangling image artifacts. ```bash theme={null} msb image prune msb image prune --yes msb image prune --format json ``` Images referenced by sandboxes or indexed snapshots are kept. `msb rmi --force` can remove a specific reference, but retains backing and cached metadata needed by those dependencies and refuses to remove a reference held by an active operation. Retained metadata files may remain after the last dependency is removed; pruning does not sweep unindexed metadata files. Prune skips cache entries held by participating pulls, imports, exports, or sandbox creation and continues with unrelated entries. Cleanup commits bounded batches, so an error can leave earlier batches completed. Shared aliases are checked together before removing their metadata file. JSON reports include `skipped_in_use`, counting busy references, manifests, and layers. Stable lock files remain in the cache. Interrupted cleanup is recovered on a later image prune or removal, with the catalog and exact file identity checked again before deletion. Concurrent cleanup requires every accessing CLI and SDK to participate in the lease protocol. Older clients can ignore these locks; coordinate a maintenance window when they share the same storage. Ordinary runtime and snapshot formats are unchanged. Pull and sandbox creation report an error if image ownership cannot be persisted in the catalog. | Flag | Description | | - | - | | `-y`, `--yes` | Skip the confirmation prompt | | `--format` | Output format (`json`) | | `-q`, `--quiet` | Suppress output | ## msb registry See [Registry commands](/cli/registry-commands) for login, logout, and stored credentials. # CLI management Source: https://docs.microsandbox.dev/cli/management Inspect the active backend, diagnose runtime setup, and manage the microsandbox CLI installation. For first-time installation, see the [CLI overview](/cli/overview#install). The msb install reference has moved to Sandbox commands. The msb uninstall reference has moved to Sandbox commands. ## msb context Show the selected backend, API endpoint, and how it was selected. Credentials are not printed. Alias: `msb ctx`. ```bash theme={null} msb context msb context --format json ``` ## msb self Diagnose, update, downgrade, or remove the CLI. `msb doctor`, `msb update` (alias: `upgrade`), and `msb downgrade` are also available at the top level. ```bash theme={null} msb doctor # Alias for msb self doctor msb doctor --fix # Try supported host setup fixes msb self doctor # Check runtime files and supported host prerequisites msb self check # Alias for doctor msb self update # Update msb and libkrunfw to latest msb self update --force # Re-download even if up to date msb self downgrade 0.6.0 # Downgrade to a supported older release msb self downgrade 0.6.0 -y # Skip downgrade confirmations msb self uninstall # Remove msb (with confirmation prompt) msb self uninstall --yes # Skip confirmation ``` | Subcommand | Description | | - | - | | `doctor` (alias: `check`) | Check runtime files, supported host virtualization prerequisites, and non-blocking host performance capabilities | | `update` (alias: `upgrade`) | Update msb and libkrunfw to the latest release and refresh command links | | `downgrade ` | Downgrade msb and compatible local state to a supported older release at or above 0.6.0, refusing unsafe downgrades before touching files or state | | `uninstall` | Remove msb, libkrunfw, and command links | `msb self update` always targets the latest release; it does not accept a version argument. Use `msb self downgrade ` to move to a supported older release. Run downgrade from the newer CLI before replacing it: the older binary does not contain rollback steps for newer migrations. If you already installed an older binary and see `database schema is newer than this msb binary`, follow the [catalog recovery steps](/migrations/v0.7#database-schema-is-newer-than-this-msb-binary). [Snapshot groups can also block downgrade](/migrations/v0.7#snapshot-groups-can-block-downgrade). Only one downgrade can run per installation. A second command fails immediately; wait for the first to finish or cancel it before retrying. Downgrade checks compatibility and requires affected sandboxes to be stopped. Releases below 0.6.0 and irreversible state changes are rejected. Database rollback creates a retained backup unless `--no-backup` is set; affected image caches are cleared unless `--keep-cache` is set. | Flag | Subcommand | Description | | - | - | - | | `--fix` | `doctor` | Try supported host setup fixes; on Windows this opens an elevated PowerShell prompt to enable Windows Hypervisor Platform without forcing an immediate reboot | | `-f`, `--force` | `update` | Re-download even if already on the latest version | | `-f`, `--force` | `downgrade` | Accepted for an explicit reinstall request; downgrade always reinstalls the target and this flag does not bypass safety checks | | `-y`, `--yes` | `downgrade` | Skip destructive-step confirmations | | `--keep-cache` | `downgrade` | Keep the image cache even when rollback metadata marks it affected | | `--no-backup` | `downgrade` | Skip the database backup before rolling back local state | | `-y`, `--yes` | `uninstall` | Skip confirmation prompt | Doctor reports supported virtualization and storage capabilities. Disabled interrupt acceleration is a performance warning, not a failed health check; doctor does not reload kernel modules. A temporary clone probe checks whether flat roots can use native copy-on-write. Probe files are removed afterward. See [Performance](/sandboxes/optimization) for details. See [Performance](/sandboxes/optimization) for interpreting these checks, choosing sandbox-level policies, and preparing the host storage and virtualization environment. # CLI overview Source: https://docs.microsandbox.dev/cli/overview Install the microsandbox CLI and manage local or cloud microVM sandboxes from your terminal. Interactive sessions are detected automatically; no `-it` flags are needed. Set an API key to use [microsandbox cloud](/cloud/overview). Each reference page marks local-only commands and cloud limitations. ## Install ```bash CLI (Linux & macOS) theme={null} curl -fsSL https://install.microsandbox.dev | sh ``` ```bash Homebrew (macOS) theme={null} brew install superradcompany/tap/microsandbox ``` ```powershell CLI (Windows) theme={null} irm https://install.microsandbox.dev/windows | iex ``` On Linux and macOS, the install script writes the runtime to `~/.microsandbox/` and creates command links in `~/.local/bin/`. It does not edit shell startup files. If `~/.local/bin` is not on your `PATH`, the installer prints the command to add it. On macOS, Homebrew provides the same CLI through the official tap. On Windows, use PowerShell. Windows support is currently in preview. Local sandboxes require Linux with glibc 2.28 or newer and KVM, an Apple Silicon Mac, or an x64 or ARM64 machine running Windows 10 or later with Windows Hypervisor Platform enabled. See [Linux troubleshooting](/troubleshooting/linux), [macOS troubleshooting](/troubleshooting/macos), or [Windows troubleshooting](/troubleshooting/windows) for setup help. Check your local setup with: ```bash theme={null} msb doctor ``` ## Command forms Use short commands for everyday work. These forms are equivalent: ```bash theme={null} msb run alpine -- echo hello msb sandbox run alpine -- echo hello msb sbx run alpine -- echo hello ``` Aliases such as `ls`, `rm`, `cp`, and `mod` also work inside `sandbox` and `sbx`. Saved-state operations are grouped under `msb snap`. The equivalent long form, `msb snapshot`, is also supported; this documentation uses `msb snap` consistently: ```bash theme={null} msb snap create ready --sandbox devbox --full msb snap restore devbox:ready --name worker msb snap ls --group devbox msb snap export devbox:ready --output ready.msb msb snap import ready.msb --group received ``` Omit `--full` to save disk state for a fresh boot. The group defaults to the source sandbox's name, so the first command creates `devbox:ready`. Full captures, live forks, groups, and archive operations are local-only. Use `msb fork devbox --names worker-a worker-b` to create children directly from the same live moment. See [Snapshots](/sandboxes/snapshots) for backend limits and resource bindings. Existing top-level `restore` and snapshot `save`/`load` commands remain supported. ## Quick reference | Commands | Purpose | | - | - | | [`run`, `create`, `start`, `stop`, `restart`](/cli/sandbox-commands) | Manage sandbox lifecycles | | [`exec`, `copy`, `logs`](/cli/sandbox-commands#msb-exec) | Run commands and access files or output | | [`ls`, `ps`, `inspect`, `metrics`](/cli/sandbox-commands#msb-ls) | Inspect sandboxes | | [`modify`, `pause`, `resume`, `fork`, `rm`](/cli/sandbox-commands#msb-modify) | Change, fork, or remove sandboxes | | [`snap`](/cli/snapshot-commands) | Save and restore state | | [`ssh`](/cli/ssh-commands) | SSH sessions, keys, and listeners | | [`volume`, `volumes`](/cli/volume-commands) | Manage named storage | | [`df`, `prune`](/cli/storage-commands) | Inspect local storage and reclaim unused runtime RAM | | [`pull`, `load`, `save`, `images`, `rmi`, `image`](/cli/image-commands) | Manage cached images | | [`registry`, `registries`](/cli/registry-commands) | Manage registry credentials | | [`context`](/cli/management#msb-context) | Show the active backend | | [`install`, `uninstall`](/cli/sandbox-commands#msb-install) | Turn sandboxes into shell commands | | [`doctor`, `update`, `downgrade`, `self`](/cli/management#msb-self) | Manage the CLI installation | | [`completion`](#shell-completion) | Generate shell completions | ## Quick start ```bash theme={null} msb create python --name worker msb exec worker -- python -c "print('hello')" msb stop worker msb rm worker ``` `msb run` without `--name` creates an ephemeral sandbox, removed when its command finishes. Named sandboxes persist. Names must contain 1–128 UTF-8 bytes. ## Global options | Flag | Description | | - | - | | `--tree` | Display the complete command tree with descriptions | | `-L, --levels ` | Limit tree depth, counting the selected root as level 0 (requires `--tree`) | | `-C, --commands` | Hide flags and arguments in the command tree (requires `--tree`) | | `-b, --brief` | Omit descriptions from the command tree (requires `--tree`) | | `--error` | Show only errors | | `--warn` | Show warnings and errors | | `--info` | Show info, warnings, and errors | | `--debug` | Show debug output | | `--trace` | Show all output including trace | ## Output formatting Progress, styled action confirmations, warnings, and errors go to stderr. Tables, inspection results, and JSON go to stdout. Empty-list messages retain their command-specific behavior: the registry empty-list message goes to stdout, while listing installed aliases produces no output when none exist. The plain `snapshot reindex` completion message also remains on stdout. Indented output uses two spaces, with nested content at four spaces. Human-readable image, snapshot, and volume sizes use binary units (KiB, MiB, GiB, TiB); JSON retains its documented numeric fields. ## Shell completion `msb completion ` prints a completion script for `bash`, `zsh`, `fish`, `elvish`, or `powershell`. Write it to the location your shell loads completions from: ```bash bash theme={null} # Requires the bash-completion package. Without it, add this line to # ~/.bashrc instead: source <(msb completion bash) mkdir -p ~/.local/share/bash-completion/completions msb completion bash > ~/.local/share/bash-completion/completions/msb ``` ```zsh zsh theme={null} mkdir -p ~/.zsh/completions msb completion zsh > ~/.zsh/completions/_msb # Add this line to ~/.zshrc before compinit runs: # fpath=(~/.zsh/completions $fpath) ``` ```fish fish theme={null} mkdir -p ~/.config/fish/completions msb completion fish > ~/.config/fish/completions/msb.fish ``` ```elvish elvish theme={null} mkdir -p ~/.config/elvish/completions msb completion elvish > ~/.config/elvish/completions/msb.elv # Add this line to ~/.config/elvish/rc.elv: # eval (slurp < ~/.config/elvish/completions/msb.elv) ``` ```powershell PowerShell theme={null} $completions = Join-Path (Split-Path $PROFILE) "completions" New-Item -Path $completions -ItemType Directory -Force | Out-Null msb completion powershell > (Join-Path $completions "msb.ps1") # Add this line to your profile ($PROFILE): # . "$PSScriptRoot/completions/msb.ps1" ``` Restart your shell. Regenerate saved completions after upgrading. ## Command tree Use `--tree` as an alternative to `--help` to see every command, subcommand, and flag at once: ```bash theme={null} msb --tree ``` You can scope it to a specific subcommand: ```bash theme={null} msb image --tree # Show only image commands msb volume --tree # Show only volume commands msb run --tree # Show all flags for run msb sandbox --tree # Show the canonical sandbox command group msb sbx run --tree # Show run flags through the group alias ``` Limit the depth or hide flags and arguments for a compact command overview: ```bash theme={null} msb --tree -L 2 msb --tree --commands msb image --tree --commands -L 1 msb --tree --brief --commands -L 2 msb --tree -Cb -L 2 ``` `-L N` (or `--levels N`) counts the selected root as level 0, so `-L 1` shows its immediate children and `-L 0` shows only the root. Omitting the limit shows all levels. At the depth limit, an inline marker such as `… 4 subcommands, 2 arguments` counts the immediate children that were collapsed; arguments include both flags and positional arguments. Hidden commands and options are excluded, and `--commands` excludes arguments from both the tree and these counts. `--brief` omits command and argument descriptions and their alignment padding, while retaining names, aliases, value placeholders, and collapse counts. It works with both `-L` and `--commands`. # Registry commands Source: https://docs.microsandbox.dev/cli/registry-commands Manage container registry credentials for local OCI image pulls with the microsandbox CLI. These commands update the local credential store; see [registry authentication](/configuration#auth-resolution-order) for credential resolution. Cloud credentials are managed separately. ## msb registry login Store a registry username and password. Without `--password-stdin`, the CLI prompts for the password. ```bash theme={null} msb registry login ghcr.io --username octocat ``` | Argument / flag | Description | | - | - | | `REGISTRY` | Registry hostname, such as `ghcr.io` | | `-u`, `--username USER` | Required registry username | | `--password-stdin` | Read the password or token from stdin | ```bash theme={null} printf '%s\n' "$GHCR_TOKEN" | \ msb registry login ghcr.io --username octocat --password-stdin ``` Passwords go in the OS credential store. Only metadata is written to the local configuration. ## msb registry logout Remove stored credentials for a registry. ```bash theme={null} msb registry logout ghcr.io ``` ## msb registry list List configured registries without printing passwords. Aliases: `msb registry ls`, `msb registries`, and `msb regs`. ```bash theme={null} msb registries ``` ## Headless authentication For CI, configure `registries.hosts..auth.password_env` in `~/.microsandbox/config.json`. Advanced setups can use `secret_name` to reference a file under `~/.microsandbox/secrets/registries/`. Credentials are resolved in this order: explicit SDK auth, OS credential store, registry auth configuration, Docker configuration, then anonymous access. # Sandbox commands Source: https://docs.microsandbox.dev/cli/sandbox-commands Create, run, connect to, and remove microVM sandboxes with the microsandbox CLI. Use the short form, such as `msb run`. `msb sandbox run` and `msb sbx run` accept the same arguments. Aliases include `ls`, `ps`, `rm`, `cp`, and `mod`. See [SSH](/cli/ssh-commands), [Snapshots](/cli/snapshot-commands), and [CLI management](/cli/management) for other commands. ## msb run Limited on cloud Create a sandbox and run its image command. Arguments after `--` replace CMD but preserve ENTRYPOINT. Unnamed sandboxes are removed when the command finishes; named sandboxes persist. ```bash theme={null} # Ephemeral: runs and cleans up msb run python -- python -c "print('hello')" # Named: persists after exit msb run --name devbox ubuntu -- bash # Override the entrypoint executable and pass its arguments after `--` msb run --entrypoint /bin/sh alpine -- -c 'echo foo; exec sleep 30' # With volumes, ports, and environment msb run --name api \ -v ./src:/app \ -v pydata:/data \ -p 8000:8000 \ -e DEBUG=true \ --label user.id=alice \ -w /app \ python # Detached: run the resolved command in the background msb run -d --name worker python -- python worker.py msb logs -f worker # Boot an idle sandbox for later exec calls msb create --name devbox python msb exec devbox -- python -c "print('hello')" # Publish on all IPv4 host interfaces instead of the default 127.0.0.1 msb run --name public-api -p 0.0.0.0:8000:8000 python ``` `--entrypoint` accepts one executable, not a shell command string. Put each argument after the image and `--`; microsandbox preserves those argument boundaries. Invoke a shell explicitly, as above, when the command uses shell syntax such as `;`, pipes, or redirects. Common flags: | Flag | Description | | - | - | | `-n`, `--name` | Sandbox name. If omitted, the sandbox is ephemeral | | `-c`, `--cpus` | Virtual CPU limit | | `--max-cpus` | Boot-time maximum possible virtual CPUs for future resize capacity | | `-m`, `--memory` | Memory limit, such as `512M` or `1G` | | `--max-memory` | Boot-time maximum hotpluggable memory, such as `2G` or `8G` | | `--thp` | Guest transparent huge-page policy: `always`, `madvise` (default), or `never` | | `--guest-clock` | `sync` (default) follows host time; `off` stops host clock updates after boot. Local-only. See [guest clock](/sandboxes/snapshots#keep-the-guest-clock) | | `--root-disk` | OCI root storage, such as `8G`, `tmpfs:2G`, `flat:8G,clone=auto`, or `./rootfs.qcow2:format=qcow2,fstype=ext4` | | `-v`, `--volume` | Mount a host path or named volume, such as `./src:/app:ro` | | `--mount-owned` | Private storage removed with this sandbox: `/data` for a directory, or `/var/lib/docker:kind=disk,size=10G` for an ext4 disk. Local-only | | `--mount-dir` | Mount a host directory: `SOURCE:DEST[:OPTIONS]`. Supports `quota` and paired `uid`/`gid` | | `--mount-file` | Mount a host file: `SOURCE:DEST[:OPTIONS]`. Supports `quota` and paired `uid`/`gid` | | `--mount-disk` | Mount a disk image: `SOURCE:DEST[:OPTIONS]` | | `--mount-named` | Create or reuse a named volume: `NAME:DEST[:OPTIONS]`. See [kind, size, and quota options](/cli/volume-commands#using-volumes-with-sandboxes) | | `-p`, `--port` | Publish a port, such as `8000:8000` for loopback-only or `0.0.0.0:8000:8000` for all host interfaces | | `--tcp-accept-queue-size` | Accept-queue depth for published TCP ports, `1` to `2147483647` (default: `1024`). See [Published ports](#published-ports) | | `--vsock` | Expose local host IPC at host CID 2 using `HOST_PATH:PORT[/stream\|/dgram]`; Unix sockets and local Windows named pipes are supported, the flag is repeatable, and stream is the default | | `-e`, `--env` | Set an environment variable | | `--label` | Attach a label for metric attribution (`KEY=VALUE`, or bare `KEY`). Repeatable | | `-w`, `--workdir` | Set the working directory | | `--entrypoint` | Override the image entrypoint executable. Pass its arguments after the image and `--` | | `-d`, `--detach` | Run the resolved image command in the background and print the sandbox name | | `--no-tty` | Disable PTY allocation and run non-interactively | | `--no-stdin` | Leave host input untouched and give the command EOF; disables automatic terminal mode and conflicts with `--tty` | | `--replace` | Replace an existing sandbox with the same name | | `--no-net` | Disable network access | | `--deployment-profile` | Select `single-tenant` or `multi-tenant` host-runtime isolation; managed backends may override it | | `--net` | Add a high-level network profile (`public`, `private`, `host`, `all`, or `none`) | | `--net-rule` | Add a network policy rule | | `--net-nat64-prefix` | Add a NAT64 `/96` prefix for network policy classification | | `--net-strict[=BOOL]` | Enabled by default; use `--net-strict=false` to opt out. Require hostname-based network allows to use inspectable request authority. Non-intercepted HTTPS fails closed when only a hostname rule allows it | | `--proxy` | Route eligible outbound traffic through a `socks4://IP:PORT` or `socks5://IP:PORT` proxy. Local-only. See [Proxies](#outbound-proxy) | | `--socks4-user-id` | Optional SOCKS4 user ID. Requires a `socks4://` proxy | | `--socks5-username`, `--socks5-password-env` | SOCKS5 username and the host environment variable containing its password. Both flags are required together | | `--secret` | Configure `NAME[:OPTIONS]@HOST[,HOST...]`; options control substitution and placeholder passthrough | | `--secret-violation-action` | Set `block`, `block-and-log`, or `block-and-terminate` for blocked placeholders | | `--tmpfs` | Mount an in-memory filesystem | | `--copy`, `--copy-file`, `--copy-dir`, `--mkdir`, `--rm` | Patch the rootfs before boot | | `--conf` | Load a sparse [sandbox configuration](/cli/configuration). Repeatable | | `--net-conf`, `--resource-conf`, `--runtime-conf`, `--fs-conf`, `--secret-conf`, `--script-conf` | Load an unwrapped, concern-specific [scoped config](/cli/configuration#scoped-config-files). Repeatable | Use `msb run --help` for the full flag list. Pass configuration files explicitly. Files merge left to right; explicit CLI arguments override them. See [Configuration](/cli/configuration). ### Flat OCI rootfs Local-only Use a complete ext4 root instead of the default layered root. Each sandbox gets a private copy of the cached base. ```bash theme={null} msb pull python --materialize flat msb run --root-disk flat:8G,clone=auto python -- python -c "print('hello')" ``` Pre-pulling is optional. Clone modes: `auto` tries native copy-on-write then sparse copy; `copy` forces a portable copy; `reflink` requires native clone support. Flat roots support pre-boot patches and local snapshots. Patches change only the private disk; snapshots preserve its layout. Set `sandbox_defaults.oci.root_disk` to use flat roots by default. See [storage optimization](/sandboxes/optimization). ### Published ports Local-only Ports bind to `127.0.0.1` by default. Use an explicit address to expose them beyond localhost. Windows may prompt for firewall access. `--port` (or `-p`) accepts inclusive, equal-length host and guest ranges, paired in ascending order: ```bash theme={null} msb create node --name media -p 0.0.0.0:10240-11264:10240-11264/udp msb create node --name services -p 8000-8002:80-82/tcp ``` The second mapping forwards host ports 8000, 8001, and 8002 to guest ports 80, 81, and 82. TCP is the default; `/udp` selects UDP. IPv6 bind addresses require brackets, for example `[::1]:8000-8002:80-82`. Range endpoints must be from 1 to 65535; reversed ranges and unequal lengths are rejected. The same syntax works with run, create, restore, and fork, and in configuration-file `ports` lists. Ranges expand into individual mappings. The UDP example opens 1,025 host sockets; large ranges require enough host socket/file-descriptor capacity and consume resources per port. A range does not reserve ports as one atomic block; existing per-port listener startup and error reporting apply. Each published TCP port's host listener queues up to 1,024 connections that the runtime has not yet accepted. Connections that arrive while the queue is full never reach the sandbox. A burst larger than the queue can fail at the proxy. For example, a reverse proxy may open one upstream connection per request for a page that loads many assets at once. Set `--tcp-accept-queue-size` to change the depth for every published TCP port of the sandbox: ```bash theme={null} msb create node --name web -p 127.0.0.1:3000:3000 --tcp-accept-queue-size 4096 ``` The host kernel caps the queue at its own limit: `net.core.somaxconn` on Linux (4,096 by default) and `kern.ipc.somaxconn` on macOS (128 by default). A larger value is accepted but has no further effect until that limit is raised. The setting requires a runtime that supports it; the SDK refuses to launch an older runtime rather than silently ignoring it. ### VSock Local-only Use the repeatable `--vsock HOST_PATH:PORT[/stream|/dgram]` flag to expose a host Unix socket or local Windows named pipe on guest host CID `2`. Stream is the default. Datagram routes preserve message boundaries and are unavailable on Windows. See [Host sockets](/networking/host-sockets) for guest connection details, limits, and SDK examples. ### Network profiles Limited on cloud `--net` is repeatable and accepts comma-separated profiles. `public`, `private`, and `host` compose; DNS through the sandbox gateway is enabled automatically and only once. `all` and `none` are terminal policies and cannot be mixed with the three positive profiles. ```bash theme={null} msb run alpine --net public msb run alpine --net "public,private" msb run alpine --net public --net private msb run alpine --net host --net-rule "deny@host:tcp:22" ``` Explicit `--net-rule` entries are evaluated before profile-generated rules, so they can narrow or deny part of a profile. `--net` conflicts with `--no-net` and the `--net-default*` flags because those select a different policy baseline. NAT64 destinations inside the well-known `64:ff9b::/96` prefix are classified by their embedded IPv4 address, so a public-only policy still blocks translated private, loopback, link-local, and metadata addresses. If your environment uses another routed NAT64 prefix, add it with repeatable `--net-nat64-prefix ` entries. Only IPv6 `/96` prefixes are accepted. ### Outbound proxy Local-only Use `--proxy` with `msb run` or `msb create` to configure one HTTP CONNECT, SOCKS4, or SOCKS5 proxy: ```bash theme={null} msb run alpine --proxy http://127.0.0.1:3128 msb run alpine --proxy socks4://127.0.0.1:1080 msb run alpine --proxy socks4://127.0.0.1:1080 \ --socks4-user-id sandbox msb run alpine --proxy socks5://127.0.0.1:1080 msb run alpine --proxy socks5://127.0.0.1:1080 \ --socks5-username sandbox \ --socks5-password-env SOCKS5_PASSWORD ``` HTTP CONNECT and SOCKS4 support TCP; SOCKS5 also supports non-DNS UDP. HTTP CONNECT does not support authentication. SOCKS5 authentication requires both flags and reads the password from the host environment at startup. Proxy URLs cannot contain credentials, paths, queries, or fragments. See [Proxies](/networking/outbound-proxy). ### Network rule syntax `--net-rule` takes one or more comma-separated rule tokens. The token grammar is: ```text theme={null} [:]@[:[:]] ``` | Field | Values | | - | - | | `action` | `allow`, `deny` | | `direction` | `egress` (default), `ingress`, `any` | | `target` | See *Targets* below | | `proto` | `tcp`, `udp`, `icmpv4`, `icmpv6`, `any` (default) | | `ports` | ``, `-`, or `any` (default) | **Targets** | Form | Example | Notes | | - | - | - | | IP / CIDR | `198.51.100.5`, `10.0.0.0/8`, `[2001:db8::/32]` | IPv6 must be bracketed | | Domain (exact) | `example.com` | Use `domain=public` to disambiguate from the `public` group | | DNS | `dns` | Semantic gateway DNS target: UDP/53 + TCP/53. May be qualified with `tcp`, `udp`, or `any` | | Domain suffix | `*.example.com`, `suffix=example.com` | Matches the apex and any subdomain at any depth. Suffixes must be at least two labels: `*.com` and `suffix=local` are rejected to prevent accidental blast radius | | Group | `public`, `private`, `loopback`, `link-local`, `meta`, `multicast`, `host`, `any` | Pre-defined destination groups (`any` is the catch-all target) | Quote rule values so the shell does not interpret wildcard characters. **Common compositions** ```bash theme={null} # Allowlist: deny by default, allow specific destinations msb run alpine --net-default deny --net-rule "allow@github.com,allow@*.githubusercontent.com" # Blocklist: allow by default, deny specific destinations msb run alpine --net-default allow --net-rule "deny@*.tracking.com,deny@*.ads.example" # Airgapped: equivalent to `--net-default deny` msb run alpine --no-net # Airgapped except one host (allowlist with --no-net sugar) msb run alpine --no-net --net-rule "allow@api.internal.corp" # Public profile with DNS disabled by a higher-priority explicit rule msb run alpine --net public --net-rule "deny@dns" ``` ## msb create Limited on cloud Create and boot a sandbox without running a command. Takes the same flags as `msb run` (except `--detach`). ```bash theme={null} msb create python --name worker -c 2 -m 1G msb create --replace python --name worker # Replace existing msb create --replace-with-timeout 30s python --name worker # Give the old one 30s to exit msb create --replace-with-timeout 0 python --name worker # SIGKILL immediately ``` ## msb snap restore Restore into a new sandbox. Disk snapshots boot fresh; full snapshots resume execution. Cloud supports disk restore. Use `msb exec` to run new commands. The existing `msb restore`, `msb sandbox restore`, and `msb sbx restore` forms accept the same flags. ```bash theme={null} msb snap restore devbox:ready --name worker --cow-mem msb exec worker -- echo hello msb snap restore ./saved.msb --name disk-copy --disk-only ``` | Flag | Description | | - | - | | `-n`, `--name` | Required destination sandbox name | | `--cow-mem` | Restore full snapshots using private CoW memory; off by default | | `--forked` | Deprecated alias for `--cow-mem`; emits a warning | | `--disk-only` | Restore only the disk from a full snapshot; conflicts with `--cow-mem` and `--forked` | | `--snapshot-base` | Exact base snapshot or archive for a dependent export | | `--allow-missing-resources` | Resume with missing external filesystems or additional disks unavailable (full restore prints warnings); restore otherwise requires their bindings | | `-v`, `--volume` | Bind `SOURCE:GUEST[:OPTIONS]`, or select a private captured disk with `GUEST` alone | | `--mount-disk` | Mount a disk image: `SOURCE:DEST[:OPTIONS]`, as in `msb create`; it wins over `-v` at the same guest path. A full restore accepts a disk only at a guest path captured in the snapshot, and the image must hold that disk's contents; use `--disk-only` to attach one at a new path | | `-p`, `--port` | Publish `[BIND:]HOST:GUEST[/tcp\|udp]` | | `--tcp-accept-queue-size` | Accept-queue depth for the child's published TCP ports (default: `1024`) | | `--vsock` | Bind `HOST_PATH:PORT[/stream\|/dgram]` | | `--external-mount-policy` | Validate supplied mappings: `strict` (default) or `relaxed` | | `--dangerously-inherit-resources` | Inherit unspecified host bindings; may share host resources | | `-u`, `--user` | Override the default user for new exec commands | | `-c`, `--cpus` | CPU count for disk boot; full restore requires the captured count | | `-m`, `--memory` | Memory for disk boot, e.g. `2G`; full restore requires the captured size | | `--security` | `default` or `restricted`, applied at disk boot; rejected for full execution restore | | `--guest-clock` | `sync` or `off`; inherits the snapshot's setting unless overridden. Supports full restores | | `--no-net` | Deny traffic in both directions by default; keeps the captured device and accepts explicit allow rules | | `--net-default` | Set both traffic defaults to `allow` or `deny` | | `--net-rule` | Repeatable host-policy rule; requires `--net-default` or `--no-net` | | `--max-tcp-connections` | Concurrent TCP limit; zero explicitly means unlimited | | `--max-udp-connections` | Concurrent UDP session limit; zero explicitly means unlimited | | `--max-connections` | Deprecated TCP-only alias; cannot be combined with `--max-tcp-connections` | | `--max-duration` | Destination sandbox lifetime bound, e.g. `10m` | | `--idle-timeout` | Destination inactivity bound, e.g. `2m` | | `-q`, `--quiet` | Hide progress, but not unavailable-resource warnings | Progress is shown by default. Memory preparation has no fixed timeout and does not consume the activation timeout. Full restore must keep captured CPU and memory settings and cannot apply a guest security profile. Use `--disk-only` to change them. Network flags replace the destination policy. `--net-rule` requires `--net-default` or `--no-net`; omitting all policy flags keeps configured defaults. Restore requires a new name and does not accept a startup command. Supply host resources explicitly when restoring or forking: * `-v /host/path:/guest/path` maps a host directory; `-v /guest/path` selects a private captured disk. * `-p HOST:GUEST` publishes a new listener. * `--vsock HOST_PATH:PORT` exposes a host service for clients to reconnect to. Restore requires recorded external filesystems and, for full restores, additional disks. `--allow-missing-resources` permits unavailable resources, but access can fail or make a guest filesystem read-only. Root and owned snapshot storage must still be complete. Full restores warn about unavailable resources even with `--quiet`; disk restores omit unmapped mounts without warnings. Cached guest memory may remain readable, but device I/O fails and can abort filesystem journals. `--external-mount-policy relaxed` tolerates supported stale-object mismatches; it does not allow missing backing. `--dangerously-inherit-resources` reuses validated source-local bindings. Direct forks retain their existing unavailable-resource behavior. See [external mounts](/sandboxes/snapshots#external-mounts). ```bash theme={null} msb snap restore saved.msb --name worker -v /srv/project:/work -v /data msb snap restore saved.msb --name inspection --allow-missing-resources ``` ## msb start Resume a stopped sandbox. Name one or more sandboxes, or select them by label. ```bash theme={null} msb start devbox msb start --label app=engine # Start every sandbox labeled app=engine ``` | Flag | Description | | - | - | | `--label` | Start every sandbox carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Unioned with any named sandboxes | | `-q`, `--quiet` | Suppress progress output | ## msb stop Limited on cloud ```bash theme={null} msb stop devbox # Wait indefinitely for graceful completion msb stop --force devbox # Force kill immediately msb stop -t 30 devbox # Fail after 30s without killing msb stop --label app=engine # Stop every sandbox labeled app=engine ``` Stop waits until shutdown completes, with no default timeout. A timeout fails without killing; a dispatched stop may still finish later. Zero expires before dispatch. Paused or unreachable sandboxes return an error; resume or force-stop them. `--force` kills immediately and may lose unsynced writes. | Flag | Description | | - | - | | `--label` | Stop every sandbox carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Unioned with any named sandboxes | | `-f`, `--force` | Force terminate immediately. Pending writes may be lost | | `-t`, `--timeout` | Total graceful-completion budget in seconds; expiry fails without killing. Omit to wait indefinitely | | `-q`, `--quiet` | Suppress progress output | ## msb pause / resume Suspend a resident sandbox without creating a snapshot, then resume it. These operations also accept the top-level `msb pause` and `msb resume` forms. ```bash theme={null} msb pause devbox msb resume devbox ``` `pause --guest-flush required` flushes captured persistent filesystems before pausing, so a later disk snapshot can reuse that boundary without resuming. The default `auto` and explicit `skip` omit optional writeback; mandatory storage barriers remain. An already-paused VM without the required flush fails rather than resuming implicitly. `resume` has no flush option. See [guest filesystem flush](/sandboxes/snapshots#guest-flushing). ## msb fork `msb branch` remains a deprecated alias. Use `fork` in new scripts. Local-only Create a local child from running or paused execution without saving a snapshot. Memory is shared through copy-on-write; each child’s memory writes stay private. ```bash theme={null} msb fork devbox -n experiment ``` Use `--names` to capture once and start several independent children from the same state: ```bash theme={null} msb fork devbox --names alice bob charlie msb fork devbox --names worker-{1..10} # Bash/Zsh expand the names ``` | Flag | Description | | - | - | | `-n`, `--name NAME` | One child name; conflicts with `--names` | | `--names NAME...` | Several child names from one capture | | `--guest-flush` | Guest writeback policy: `auto` (default), `required`, or `skip`; see [advanced guest flushing](/sandboxes/snapshots#guest-flushing) | | `--integrity` | Record disk content hashes | | `--mount-disk` | Rebind a captured disk to a host image: `SOURCE:DEST[:OPTIONS]`, as in `msb create`; it wins over `-v` at the same guest path | | `-q`, `--quiet` | Suppress progress | Both fork forms accept `--guest-flush auto|required|skip`. Auto and skip preserve dirty memory without flushing root or owned block filesystems; required adds writeback. Host-backed directory synchronization and host disk barriers remain in effect. Volume, port, TCP accept queue size, user, vsock, inheritance, and mount-policy flags match [`restore`](#msb-restore). A fork cannot add a new block device. `--mount-disk` only rebinds a captured disk, such as a named disk volume, at `DEST` to a host image consistent with the captured state. Images are attached directly, so batch forks must not share a writable image. See [fork disk bindings](/sandboxes/snapshots#forking) for details. Batch forking captures once. Results follow input order; failed children produce a nonzero exit status without removing successful ones. ## msb restart Limited on cloud Stop and start one or more sandboxes. Running, draining, and paused sandboxes are stopped first, then started from their persisted configuration. Stopped, crashed, and created sandboxes skip the stop phase and are started directly. ```bash theme={null} msb restart devbox msb restart api worker msb restart --label app=engine msb restart --force devbox msb restart -t 30 devbox ``` `msb restart --force` kills immediately. Otherwise `--timeout` bounds graceful completion; expiry fails without killing or starting a replacement. Unlike standalone Stop, Restart retains its explicit default budget of ten seconds. | Flag | Description | | - | - | | `--label` | Restart every sandbox carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Unioned with any named sandboxes | | `-f`, `--force` | Force terminate immediately before starting again. Pending writes may be lost | | `-t`, `--timeout` | Total graceful-completion budget in seconds; expiry fails without killing. Defaults to 10 | | `-q`, `--quiet` | Suppress progress output | ## msb wait Wait for an existing sandbox to reach `Stopped` or `Crashed`. Also available as `msb sandbox wait` and `msb sbx wait`. Use `msb run --name worker --detach …` to keep the sandbox available for a later `msb wait`; unnamed runs are removed when they finish. ```bash theme={null} msb wait worker msb wait worker --timeout 30s msb wait worker --timeout 5m --format json ``` | Flag | Description | | - | - | | `-t`, `--timeout` | Stop waiting after a duration such as `500ms`, `30s`, `5m`, or `1h`. Without this flag, wait indefinitely | | `--format json` | Emit the observed terminal state as JSON | The timeout covers lookup and waiting. It returns an error without stopping the sandbox. Missing sandboxes return an error; stopped or crashed sandboxes return immediately. A successful wait means the sandbox stopped or crashed, not that its workload succeeded. Text output shows the sandbox name and status. JSON includes `name`, `status`, `terminal`, `exit_code`, `signal`, `observed_at`, and `source`. Exit codes and signals are currently unavailable (`null`); `observed_at` records when the terminal state was observed. ## msb ping Local-only Check whether running sandboxes respond. Add `--touch` to refresh the idle timer on success. ```bash theme={null} msb ping devbox msb ping api worker msb ping --label app=engine msb ping api --touch ``` | Flag | Description | | - | - | | `--label` | Ping every sandbox carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Unioned with any named sandboxes | | `--touch` | Refresh the sandbox idle timer after a successful ping | | `-q`, `--quiet` | Suppress progress output | ## msb touch Local-only Refresh the idle timer for one or more running sandboxes. ```bash theme={null} msb touch devbox msb touch api worker msb touch --label app=engine ``` | Flag | Description | | - | - | | `--label` | Touch every sandbox carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Unioned with any named sandboxes | | `-q`, `--quiet` | Suppress progress output | ## msb modify Local-only `msb mod` is a shorter alias for `msb modify`. Change a running sandbox's configuration. Every change is planned and applied all-or-nothing. CPU and memory resize live within the `max_cpus` / `max_memory` ceilings; other changes that can't apply live need `--restart` or `--next-start`. ```bash theme={null} msb modify api -c 4 # Live when 4 <= max_cpus msb modify api -e MODE=prod --restart # Restart to apply now msb modify api --max-memory 16G --next-start # Raise the ceiling on next start msb modify api --cpus 8 --dry-run # Show the plan, apply nothing ``` Like create/run, modify accepts `-c`/`--cpus`, `-m`/`--memory`, `-e`/`--env`, and `-w`/`--workdir`. Set `--max-cpus` and `--max-memory` at creation to leave room for live growth. They default to the initial CPU and memory allocation; increasing the ceilings requires a restart. Resize can take time. The output and JSON `resize_status` report `applied`, `converging`, `guest-refused`, or `failed`. With `guest-refused`, the host still enforces the new limit. Env and workdir changes on a running sandbox apply to future execs only; running processes keep their current environment. The plan reports this as a warning. `--secret` reads the same-named host environment variable; inline values are rejected. Options are `query`, `body`, `no-headers`, `headers=[FIELD,...]` (substitute only in those header fields; `headers=*` restores all headers, `*` cannot be combined with named fields, and `headers=` cannot be combined with `no-headers`), and `passthrough=HOST` or `passthrough=[HOST,...]`. Restrict `headers` to the credential header the API reads, since substituting in every header lets a reflecting endpoint return the secret to the guest. Repeated declarations merge. See [secret updates](/sandboxes/secrets#update-secrets). | Flag | Description | | - | - | | `--cpus` | Desired effective vCPU count | | `--max-cpus` | Boot-time maximum possible vCPUs (restart-backed) | | `--memory` | Desired effective guest memory, such as `512M` or `4G` | | `--max-memory` | Boot-time maximum hotpluggable memory (restart-backed) | | `--env`, `--env-rm` | Set (`KEY=VALUE`) or remove an environment variable for future execs | | `--label`, `--label-rm` | Set (`KEY=VALUE`) or remove a label | | `--workdir` | Working directory for future execs | | `--secret`, `--secret-rm` | Add or rotate a secret (`NAME[:OPTIONS]@HOST[,HOST...]`), or remove one | | `--secret-violation-action` | Set the sandbox-wide blocking action for placeholder violations | | `--dry-run` | Show the plan without applying anything | | `--next-start` | Save changes for the next start without mutating a running VM | | `--restart` | Restart if needed so restart-required changes become active now | | `--format json` | Emit the plan/result as JSON | See [live changes](/sandboxes/tuning) for resize behavior. Use `msb modify --help` for the full flag list. ### Compaction Merge sealed layers in the local root and owned disks. Run separately from configuration changes; the sandbox must be running or fully stopped. ```bash theme={null} msb modify api --compact --dry-run msb modify api --compact --layers 3 ``` | Flag | Description | | - | - | | `--compact` | Merge sealed layers; excludes named/external disks and directories | | `--layers N` | Oldest sealed layers to merge, including the base. Minimum two; omit for all | | `--disk PATH` | Select one owned disk; `/` selects the root | | `--root-disk-only` | Select only the root; conflicts with `--disk` | | `--dry-run` | Preview per-disk results without writing | The writable layer is excluded. Fewer than two sealed layers or no eligible disks means no change. See [compaction recovery](/sandboxes/snapshots#compact-disks) before applying. ## msb exec Execute a command inside a sandbox. An already-running sandbox stays running. Stopped or crashed sandboxes start temporarily and stop again before the command returns, including after execution errors. Invalid environment, resource-limit, or timeout arguments fail before startup. ```bash theme={null} msb exec devbox -- python -c "print('hello')" msb exec devbox -- ls -la /app ``` Use `--detach` to keep a command running after you disconnect. It requires a running local sandbox and prints a job ID after startup is confirmed. See [background jobs](/sandboxes/commands#managed-jobs) for logs, reattachment, and lifecycle details. | Flag | Description | | - | - | | `-d`, `--detach` | Run as a background job; requires a running local sandbox and conflicts with `--stream` | | `-t`, `--tty` | Allocate a pseudo-terminal (enables colors, line editing) | | `--no-tty` | Disable PTY allocation and run non-interactively | | `--no-stdin` | Leave host input untouched and give the command EOF; disables automatic terminal mode and conflicts with `--tty` | | `--stream` | Forward stdin and flush output incrementally without a PTY; requires piped stdin or `--no-stdin` | | `-e`, `--env` | Set an environment variable (`KEY=VALUE`) | | `-w`, `--workdir` | Override working directory | | `-u`, `--user` | Run the command as the specified guest user | | `--timeout` | Kill the command after this duration (e.g. `30s`, `5m`, `1h`) | | `--rlimit` | Set a POSIX resource limit (e.g. `nofile=1024`, `nproc=64`) | | `-q`, `--quiet` | Suppress progress output | Resource limits apply inside the guest before switching to `--user`, so non-root commands can use explicitly raised hard limits. The override affects only that command and its descendants; it does not change the guest agent's limits or the host's limits. For example, allow a command to lock up to 64 MiB for registered `io_uring` buffers: ```bash theme={null} msb exec --user 1000:1000 --rlimit memlock=67108864 devbox -- ./worker ``` The CLI auto-detects whether stdin is a terminal. When interactive, `msb exec` uses `attach` mode (TTY, line editing). When piped, it forwards input while the command runs and captures output until the command exits. Use `--no-tty` to force captured, non-interactive execution even from a terminal; terminal input is not forwarded in that mode. Use `--stream` for an ongoing conversation with a guest process, such as an ACP agent. It returns output as it arrives instead of waiting for command completion. Piped commands can exit or time out while the host input pipe is still open. Commands that read until EOF, such as `cat`, still need their input closed to finish normally. Use `--no-stdin` to leave input available to the calling script and give the guest immediate EOF: ```bash theme={null} while IFS= read -r sandbox; do msb exec --no-stdin "$sandbox" -- echo ready done < sandboxes.txt ``` Combine `--no-stdin` with `--stream` when you want live output without forwarding input. Omit `--no-stdin` for ACP agents, which need input from the IDE. ## msb copy Copy files between the host and a sandbox. ```bash theme={null} msb copy ./local.txt devbox:/tmp/local.txt msb copy devbox:/tmp/out.txt ./out.txt msb copy devbox:/tmp/a devbox:/tmp/b msb copy devbox:/tmp/a otherbox:/tmp/a ``` Supports host-to-sandbox, sandbox-to-host, and copies within or between sandboxes. Stopped sandboxes start temporarily, as with [`msb exec`](#msb-exec). Alias: `msb cp`. | Flag | Description | | - | - | | `-q`, `--quiet` | Suppress progress output | ## msb logs Limited on cloud Read output from running or stopped local sandboxes. On cloud, use `--follow` to stream a running sandbox; historical reads and time filters are unavailable. ```bash theme={null} # Captured user-program output (default sources: stdout + stderr + output) msb logs devbox # Tail and follow msb logs devbox --tail 100 msb logs devbox -f --grep ERROR # Time-bounded msb logs devbox --since 5m msb logs devbox --since 2026-04-30T20:00:00Z --until 5m # JSON Lines passthrough: feed to jq, vector, etc. msb logs devbox --json | jq 'select(.s == "stderr")' # Multi-session view: prefix each line with [id:N] so you can tell sessions apart msb logs devbox --show-id # Color each session's output a distinct color (implies --show-id) msb logs devbox --color-sessions # Include runtime/kernel diagnostics msb logs devbox --source system msb logs devbox --source all # everything, chronologically merged ``` | Flag | Description | | - | - | | `--tail` | Show only the last N entries | | `--since` | Show entries at or after this time (RFC 3339 or relative `5m`/`2h`/`1d`) | | `--until` | Show entries strictly before this time (same formats) | | `-f`, `--follow` | Follow new entries | | `--timestamps` | Prefix each line with the entry timestamp | | `--source` | Sources to include: `stdout`, `stderr`, `output`, `system`, `all`. Repeat or comma-separate. Default: `stdout,stderr,output` | | `--grep` | Client-side regex filter on the entry body | | `--json` | Emit raw JSON Lines without decoding (one entry per line) | | `--raw` | Opt into base64 encoding for non-UTF-8 bytes | | `--show-id` | Prefix each line with `[id:N]` (the session correlation id) | | `--color-sessions` | Color each session's lines a distinct color (implies `--show-id`) | | `--color` | ANSI handling: `auto` (default), `always`, `never` | | `--no-color` | Alias for `--color=never` | The `s` field in JSON output identifies the source: | Source | Contents | | - | - | | `stdout`, `stderr` | Separate streams from commands run without a terminal | | `output` | Combined stdout and stderr from a terminal session | | `system` | Lifecycle markers and runtime/kernel diagnostics | If startup failed, logs include the failure stage and a troubleshooting hint. ## msb list List all stored sandboxes. ```bash theme={null} msb ls # All sandboxes (running and stopped) msb ls --running # Running sandboxes only msb ls --stopped # Stopped sandboxes only msb ls --label app=engine # Only sandboxes labeled app=engine msb ls --format json # JSON output msb ls -q # Names only ``` | Flag | Description | | - | - | | `--running` | Show only running sandboxes | | `--stopped` | Show only stopped sandboxes | | `--label` | Show only sandboxes carrying this label (`KEY=VALUE`). Repeatable; AND-matched | | `--format` | Output format (`json`) | | `-q`, `--quiet` | Show only sandbox names | ## msb status Show sandbox status with process details. ```bash theme={null} msb ps # Running sandboxes msb ps my-app # Single sandbox msb ps -a # All sandboxes (including stopped) msb ps --format json # JSON output ``` | Flag | Description | | - | - | | `-a`, `--all` | Show all sandboxes, not just running ones | | `--label` | Show only sandboxes carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Not combinable with a sandbox name | | `--format` | Output format (`json`) | | `-q`, `--quiet` | Show only sandbox names | `CPUS` and `MEM` show current allocation / maximum resize capacity. For measured usage, use [`msb metrics`](#msb-metrics). ## msb metrics Local-only Show live CPU, memory, disk, network, and optional upper disk metrics for running sandboxes. ```bash theme={null} msb metrics # All running sandboxes (one-shot table) msb metrics my-app # Single sandbox, in any state msb metrics --watch # Refresh the table in place (like docker stats) msb metrics --follow # Stream JSON Lines, one object per sandbox per tick msb metrics --all # Include recently exited sandboxes msb metrics --sort cpu # Sort by CPU instead of name msb metrics --format json # One-shot JSON output ``` | Flag | Description | | - | - | | `-w`, `--watch` | Continuously refresh the table in place. Ctrl+C to quit. Requires a terminal | | `-f`, `--follow` | Stream one JSON Lines object per sandbox per interval to stdout | | `--interval` | Refresh interval for `--watch`/`--follow` (e.g. `500ms`, `2s`). Default `1s` | | `-a`, `--all` | Include `exited` rows: terminal metrics preserved in the registry until the slot is reused | | `--sort` | Sort rows by `name` (default), `cpu`, or `mem` | | `--format` | Output format (`json`) | | Column | Meaning | | - | - | | `STATE` | `running`: fresh sample; `stalled`: no sample for three sampling intervals; `exited`: final sample | | `CPU` | Busy cores / allocated cores, such as `0.80 / 2c` | | `MEM` | Guest-used memory / current memory limit | | Disk and network rates | Per-second change; exited rows show cumulative totals | Limits reflect live resizes. One-shot output samples twice to calculate rates. JSON and follow output keep cumulative counters and include `state` and `cpus`. ## msb inspect Limited on cloud Show detailed configuration and status. ```bash theme={null} msb inspect devbox msb inspect devbox --format json ``` | Flag | Description | | - | - | | `--format` | Output format (`json`) | ## msb remove Remove one or more sandboxes and their associated state. ```bash theme={null} msb rm devbox msb rm --force devbox # Stop and remove in one step msb rm worker-1 worker-2 # Remove multiple msb rm --force --label app=engine # Remove every sandbox labeled app=engine ``` | Flag | Description | | - | - | | `--label` | Remove every sandbox carrying this label (`KEY=VALUE`). Repeatable; AND-matched. Unioned with any named sandboxes | | `-f`, `--force` | Stop the sandbox if running, then remove it | | `-q`, `--quiet` | Suppress progress output | ## msb install Install a sandbox as a system command. Creates an executable in `~/.microsandbox/bin/` that launches `msb run` with the specified image and options. ```bash theme={null} msb install ubuntu # Install as 'ubuntu' command msb install --name nodebox node # Custom command name msb install --tmp alpine # Fresh sandbox every invocation msb install -c 2 -m 1G python # With resource limits msb install --list # List installed commands ``` By default, each run reuses the same sandbox, keeping its files and mounts. Add `--tmp` to create a fresh sandbox each time and delete it on exit. Files in mounted host folders are kept. To mount the folder you run the command from: ```bash theme={null} msb install --tmp --name project-shell --mount-dir ./:/workspace:rw -w /workspace alpine -- sh ``` Run `project-shell` from any folder to open it at `/workspace` inside the sandbox. Keep `./` as written so the path is resolved on each run, rather than passing a full path during installation. | Flag | Description | | - | - | | `-n`, `--name` | Command name for the alias (defaults to image name) | | `-c`, `--cpus` | Number of virtual CPUs to allocate | | `-m`, `--memory` | Amount of memory (e.g. `512M`, `1G`) | | `-v`, `--volume` | Mount a host path or named volume (`SOURCE:DEST[:OPTIONS]`, e.g. `./src:/app:ro,noexec`) | | `--mount-dir` | Mount a host directory: `SOURCE:DEST[:OPTIONS]`. Supports `quota` and paired `uid`/`gid` | | `--mount-file` | Mount a host file: `SOURCE:DEST[:OPTIONS]`. Supports `quota` and paired `uid`/`gid` | | `--mount-disk` | Mount a disk image: `SOURCE:DEST[:OPTIONS]` | | `--mount-named` | Create or reuse a named volume: `NAME:DEST[:OPTIONS]`. See [kind, size, and quota options](/cli/volume-commands#using-volumes-with-sandboxes) | | `--security` | In-guest security profile (`default` or `restricted`) | | `-w`, `--workdir` | Working directory inside the sandbox | | `--shell` | Shell for interactive sessions | | `-e`, `--env` | Set an environment variable (`KEY=VALUE`) | | `-f`, `--force` | Overwrite an existing alias with the same name | | `--no-pull` | Don't pull the image before installing | | `--tmp` | Create a fresh sandbox on every invocation and remove it on exit; host-mounted files persist | | `-l`, `--list` | List all installed sandbox commands | | `--conf` | Load an explicit sparse [sandbox configuration](/cli/configuration). Repeatable | | `--net-conf`
`--resource-conf`
`--runtime-conf`
`--fs-conf`
`--secret-conf`
`--script-conf` | Load an explicit [scoped config](/cli/configuration#scoped-config-files). Repeatable | ## msb uninstall Remove an installed sandbox command. ```bash theme={null} msb uninstall nodebox msb uninstall ubuntu alpine # Remove multiple ``` # Snapshot commands Source: https://docs.microsandbox.dev/cli/snapshot-commands Capture, inspect, restore, and transfer sandbox snapshots with the microsandbox CLI. Limited on cloud Manage saved snapshots with `msb snap`. See the [snapshot guide](/sandboxes/snapshots) for workflows. Local selectors accept a group head, `group:member`, an unambiguous ID or digest, or an artifact path. On cloud, use the snapshot reference returned by the command. ## msb snap create Capture disk state. Add `--full` to include memory and running processes. ```bash theme={null} msb snap create ready --sandbox worker ``` | Argument / flag | Description | | - | - | | `NAME` | Positional member name; generated when omitted | | `-n`, `--name NAME` | Set the name instead of the positional argument; do not supply both | | `--sandbox NAME` | Required source sandbox; `--from-sandbox` remains an alias | | `--group GROUP` | Local group; defaults to the source sandbox’s name | | `--dest-dir DIR` | Parent directory for local groups | | `-o`, `--output PATH` | Capture directly to an archive; conflicts with `--dest-dir` and does not accept `--group` | | `--full` | Capture disk, memory, and execution state from a running or paused source | | `--guest-flush` | Guest writeback policy: `auto` (default), `required`, or `skip`; see [guest flushing](/sandboxes/snapshots#guest-flushing) | | `--integrity` | Record content hashes for later verification | | `--label KEY=VALUE` | Attach a label; repeatable | | `--plain-tar` | Write uncompressed tar; requires `--output` | | `-f`, `--force` | Overwrite an archive output; not allowed for installed members | | `-q`, `--quiet` | Suppress output | Local disk capture accepts running, paused, stopped, or crashed sources. Cloud requires a stopped persistent source. ```bash theme={null} msb snap create snap --sandbox worker --full msb snap create ready --sandbox worker --integrity msb snap create ready --sandbox worker -o ready.msb ``` Guest flushing is shared by the CLI and SDKs. See [guest flushing](/sandboxes/snapshots#guest-flushing) for policies and examples. ## msb snap restore Restore a saved snapshot into a new sandbox. Disk snapshots boot fresh; full snapshots resume captured execution. ```bash theme={null} msb snap restore worker:ready --name restored ``` `--name` is required. See [restore options](/cli/sandbox-commands#msb-snap-restore) for memory sharing, disk-only restore, and resource bindings. Existing top-level `restore` commands remain supported. ## msb snap ls List snapshots. Use `--group` to filter a local group; it is unavailable on cloud. ```bash theme={null} msb snap ls msb snap ls --group worker ``` | Flag | Description | | - | - | | `--group GROUP` | Show only snapshots in this local group | | `--format json` | JSON output | | `-q`, `--quiet` | Show only digests | ## msb snap inspect Show snapshot metadata. Add `--verify` to check recorded content hashes. ```bash theme={null} msb snap inspect worker:ready msb snap inspect worker:ready --verify ``` ## msb snap verify Check recorded content integrity. Local-only; capture with `--integrity` to record disk hashes. ```bash theme={null} msb snap verify worker:ready ``` Without disk hashes, size and structure checks cannot detect same-size corruption. Full snapshots also validate their memory and execution objects. See [integrity](/sandboxes/snapshots#verify-integrity). ## msb snap rm Delete one or more snapshots. ```bash theme={null} msb snap rm worker:ready ``` | Flag | Description | | - | - | | `-f`, `--force` | Remove even when indexed children exist | | `-q`, `--quiet` | Suppress output | If other group members remain, select another head before removing the current one. `--force` does not bypass this rule. If an indexed artifact was deleted outside Microsandbox, removing it by its indexed path clears the stale entry. For a grouped snapshot, this requires the whole group directory to be gone; a surviving group still needs its head and membership checks. Indexed children still require `--force`. Removal also refuses an installed copy held by an active restore, export, verification, or import dependency read. `--force` does not bypass active readers. Independent copies of the same snapshot have independent leases. On Unix, copies sharing a hardlinked descriptor conservatively share reader protection; Windows normally protects each installed directory entry independently. Metadata handles alone do not keep snapshots busy. Saving or removing through a retained SDK handle rejects a replacement artifact at the same path. Deletion atomically retires the artifact directory before removing its contents. A later snapshot listing or removal can recover interrupted cleanup without deleting a new artifact at the original path. Unix readers lock the existing descriptor. Windows readers normally lock an entry-side coordination file outside the removable directory and fall back to the descriptor when an external parent is read-only. Publication and deletion require writable destinations for their coordination records. Concurrent cleanup requires participating SDKs and CLIs; coordinate maintenance when older clients share the storage. ## msb snap head Read a local group’s head, or select a member as its head. ```bash theme={null} msb snap head worker msb snap head worker:ready ``` Use `--format json` for structured output. The first capture sets the head; later captures advance it only when ancestry proves they descend from it. See [snapshot groups](/sandboxes/snapshots#snapshot-groups). ## msb snap export Export a local snapshot to a compressed `.msb` archive. The `save` alias remains supported. ```bash theme={null} msb snap export worker:ready --output ready.msb --with-image ``` | Flag | Description | | - | - | | `-o`, `--output PATH` | Output archive path; a positional path is also accepted | | `--with-image` | Bundle the OCI image for offline restore | | `--with-parents` | Include the parent chain | | `--plain-tar` | Write uncompressed tar | | `--since BASE` | Omit disk layers and RAM objects supplied by an exact base | | `--last-layers N` | Export the newest N sealed root-disk layers; the omitted base is needed on import | `--since`, `--last-layers`, and `--with-parents` are mutually exclusive. Export preserves recorded hashes but does not verify them. See [incremental exports](/sandboxes/snapshots#export-changes) for base requirements. ## msb snap import Import one or more local archives. The `load` alias remains supported. Dependencies resolve regardless of input order; all members are validated before publication. Snapshot publication records image ownership before exposing the installed artifact and reports catalog failures. Pending publication and deletion recovery runs during snapshot listing; image pruning also reconciles pending publication. ```bash theme={null} msb snap import ready.msb ``` | Flag | Description | | - | - | | `--dest DIR` | Parent directory for groups; defaults to the configured snapshot store | | `--group GROUP` | Destination group; generated when omitted | | `--base SNAPSHOT` | External snapshot or standalone archive for missing dependencies | | `--set-head` | Select the imported tip even with divergent ancestry; requires a unique tip | Dependencies come from the batch, matching members in the named group, or `--base`. Import preserves recorded hashes; run `verify` to check them. ```bash theme={null} msb snap import changes.msb base.msb --group received msb snap import changes.msb --base worker:ready --group received msb snap import experiment.msb --group worker --set-head ``` ## msb snap reindex Rebuild the local snapshot index from artifacts on disk. An omitted directory uses the configured snapshot store. ```bash theme={null} msb snap reindex msb snap reindex /mnt/snapshots ``` ## Related commands | Command | Purpose | | - | - | | [`msb fork`](/cli/sandbox-commands#msb-sandbox-fork) | Copy running execution without saving a snapshot | | [`msb modify --compact`](/cli/sandbox-commands#compaction) | Merge sealed disk layers | # SSH commands Source: https://docs.microsandbox.dev/cli/ssh-commands Connect to running sandboxes and serve SSH endpoints with the microsandbox CLI. See [SSH](/sandboxes/ssh) for shell, remote command, and SFTP workflows. ## msb ssh Start a native SSH client session into a sandbox. With no remote command, this opens an interactive shell. With `--`, the remaining tokens are joined into the remote shell command. ```bash theme={null} msb ssh devbox msb ssh devbox -- uname -a msb ssh --name serve -- uptime ``` | Argument | Description | | - | - | | `sandbox` | Sandbox name, up to 128 UTF-8 bytes | | `-n`, `--name NAME` | Explicit sandbox name, up to 128 UTF-8 bytes; useful when the name collides with `serve`, `authorize`, or `help` | | `--inactivity-timeout DURATION` | Disconnect after this much SSH inactivity; accepts values such as `30s`, `10m`, or `1h`. Use `0` to disable | | `--no-inactivity-timeout` | Disable the SSH inactivity timeout | | `-- COMMAND...` | Remote command to run through the sandbox shell | ## msb ssh authorize Add a public key to microsandbox's SSH authorization file. ```bash theme={null} msb ssh authorize --file ~/.ssh/id_ed25519.pub msb ssh authorize --key "ssh-ed25519 AAAA... user@host" cat ~/.ssh/id_ed25519.pub | msb ssh authorize --stdin ``` | Flag | Description | | - | - | | `--file PATH` | Read one public key from a file | | `--key KEY` | Read one public key from the flag value | | `--stdin` | Read one public key from stdin | The default authorization file is `/ssh/authorized_keys`, or `~/.microsandbox/ssh/authorized_keys` when `MSB_HOME` is unset or empty. The file is created with private permissions. ## msb ssh serve Local-only Serve a sandbox over SSH for external OpenSSH, SFTP, local TCP forwarding, dynamic TCP forwarding, or `ProxyCommand` clients. ```bash theme={null} msb ssh serve devbox msb ssh serve devbox --host 127.0.0.1 --port 2222 msb ssh serve devbox --stdio ``` | Flag | Description | | - | - | | `--host HOST` | Listener host. Defaults to `127.0.0.1` | | `-p`, `--port PORT` | Listener port. Defaults to `2222` | | `--stdio` | Serve one SSH transport over stdin/stdout for OpenSSH `ProxyCommand` | | `--inactivity-timeout DURATION` | Disconnect each connection after this much SSH inactivity. Use `0` to disable | | `--no-inactivity-timeout` | Disable the SSH inactivity timeout | Listener mode accepts ordinary OpenSSH clients: ```bash theme={null} ssh -p 2222 root@127.0.0.1 sftp -P 2222 root@127.0.0.1 ssh -p 2222 -L 8080:127.0.0.1:80 root@127.0.0.1 ssh -p 2222 -D 1080 root@127.0.0.1 ``` Forwarded TCP connections originate inside the guest through microsandbox's agent. Sandbox network policy still applies, and guest loopback addresses refer to the sandbox, not the host. Reverse forwarding (`-R`) and stream-local forwarding are not supported. `--stdio` is for clients that spawn `msb` as a transport bridge: ```sshconfig theme={null} Host devbox.msb User root ProxyCommand msb ssh serve devbox --stdio ``` ## msb ssh connect Explicit form of [`msb ssh`](#msb-ssh), with the same arguments and options. ```bash theme={null} msb ssh connect devbox ``` All SSH commands inherit `ssh.inactivity_timeout_secs` from user configuration when neither timeout flag is present. The built-in default is 10 minutes. A [managed timeout](/configuration#ssh) takes precedence over both flags, including `--no-inactivity-timeout`, for local and cloud sessions. ## SSH state | Path | Purpose | | - | - | | `/ssh/host_ed25519` | Per-sandbox SSH host private key, created on first serve | | `/ssh/authorized_keys` | Public keys allowed to connect | When `MSB_HOME` is unset or empty, `` is `~/.microsandbox`. # Storage commands Source: https://docs.microsandbox.dev/cli/storage-commands Check local storage usage and clean up unused memory files. Check disk usage with `msb df` and remove unused runtime memory files with `msb prune`. Both commands are local-only. For application code, see [SDK storage](/sdk/storage). ## msb df Show storage used by images, snapshots, sandboxes, volumes, and runtime memory files: ```bash theme={null} msb df ``` Add `--verbose` for individual paths and details, or `--format json` for structured output. Use `msb inspect NAME` or `msb snap inspect REF` to inspect one sandbox or snapshot. `RECLAIMABLE` shows unused runtime memory files eligible for cleanup. Reported sizes may differ from the disk space actually freed, especially when files share data. The table always includes images, durable snapshots, branch memory, snapshot memory, sandboxes, and volumes, even when their measured usage is zero. `--verbose` adds object paths, allocated-block observations, and reasons entries are retained or could not be measured. Unknown measurements appear as `-` in tables and `null` in JSON. | Column | Meaning | | - | - | | `TYPE` | Managed storage category | | `COUNT` | Indexed objects, or published backing files for memory caches | | `IN USE` | Observed owners where ownership can be checked; unknown for categories without reader leases | | `LOGICAL SIZE` | Regular-file lengths, with hard links counted once per category on Unix | | `RECLAIMABLE` | Logical bytes currently eligible for runtime-cache cleanup | Image references share layers, so image accounting scans the shared cache instead of summing each image's advertised size. Managed-directory totals include metadata and unindexed files. Indexed external snapshot directories are included; host bind mounts, external linked payloads, unindexed external snapshots, and anonymous Linux RAM are excluded. Concurrent filesystem activity can change measurements while a scan runs. Logical file lengths and allocated blocks do not measure unique physical storage on filesystems with shared copy-on-write extents. Removing 1 GiB of logical data may free less physical space. There is no combined total when categories may overlap. ## msb prune Preview cleanup, then run it: ```bash theme={null} msb prune --dry-run msb prune ``` Cleanup removes unused memory files from branches and cached snapshot restores. It keeps saved snapshots, sandbox disks, named volumes, and images. To clean up images, use [`msb image prune`](/cli/image-commands#msb-image-prune). Files still in use are skipped. Without `--yes`, cleanup asks for confirmation in an interactive terminal. The result can differ from the preview if files become active in the meantime. * `--dry-run`: preview without deleting files. * `--yes`: skip the confirmation prompt. * `--older-than 10m`: only consider files at least ten minutes old. Accepts a nonnegative integer with `s`, `m`, `h`, or `d`; defaults to `0s`. * `--format json`: return a structured report. * `-q`, `--quiet`: suppress successful human output. Does not skip confirmation and cannot be combined with JSON. Prune only removes recognized, published runtime RAM files with no live backing pin or pending branch handoff. Stable lock files and capture staging directories are retained. The age filter uses file modification times, which clones can inherit; ownership is checked again before removal. JSON includes `entries`, `files_removed`, `logical_bytes_removed`, and `physical_bytes_reclaimed`. The latter remains `null`: the command does not claim physical storage savings. Entries explain `in_use`, `pending_handoff`, `too_young`, `missing_handoff_lock`, `changed`, or `error` decisions. An error report retains successful removal counts and exits unsuccessfully; a caller can retry later. Dry-run entries use `reclaimable` and removal counters remain zero. ## Automatic branch cleanup Unused branch memory files are also cleaned up automatically when possible. Paused sandboxes keep their backing files. Cached snapshot memory stays available for faster restores until you explicitly prune it. Branch backing is reclaimed best-effort after its last tracked SDK or baseline owner releases it, provided no other pin or handoff remains. Paused sandboxes retain their backing. Runtime process exit and abrupt termination release kernel pins. After a graceful stop, cleanup tries the stopped branch's exact backing file and then traverses the branch cache in bounded passes without pauses between them; CLI commands wait for that traversal after the graceful-stop result, while SDK callers can continue without waiting. A subsequent branch also triggers a bounded sweep for leftovers, limited to once every 30 seconds within one SDK process. Automatic cleanup targets branch memory. Unused snapshot RAM realizations remain available for warm restores until explicitly pruned. Neither path changes memory bytes, snapshot formats, or checkpoint sparsity. For storage reporting and cleanup in application code, see [SDK storage](/sdk/storage). # Volume commands Source: https://docs.microsandbox.dev/cli/volume-commands Create, mount, and manage persistent sandbox volumes with the microsandbox CLI. Named volumes persist independently of sandboxes. Local volumes default to `~/.microsandbox/volumes/`. ## msb volume create Limited on cloud ```bash theme={null} msb volume create my-data msb volume create --name my-data msb volume create docker-data --kind disk --size 10G ``` | Flag | Description | | - | - | | `-n`, `--name` | Volume name, as an alternative to the positional name | | `--kind` | Volume kind (`dir` or `disk`; default `dir`) | | `--size` | Disk capacity for `--kind disk` (e.g. `100M`, `1G`, `10G`) | | `-q`, `--quiet` | Suppress output (only print the volume name) | ## msb volumes ```bash theme={null} msb volumes msb volumes --format json msb volumes -q # Names only ``` Expanded form: `msb volume ls`. The shorter plural alias `msb vols` is also available. | Flag | Description | | - | - | | `--format` | Output format (`json`) | | `-q`, `--quiet` | Show only volume names | ## msb volume inspect Local-only ```bash theme={null} msb volume inspect my-data ``` ## msb volume rm ```bash theme={null} msb volume rm my-data msb volume rm cache-1 cache-2 # Remove multiple ``` | Flag | Description | | - | - | | `-q`, `--quiet` | Suppress output | ## Using volumes with sandboxes Use `NAME:GUEST_PATH` to mount a volume. Locally, missing named volumes are created and compatible existing volumes are reused. On cloud, create the volume first. ```bash theme={null} # Create or reuse a directory-backed named volume, then mount it msb run --name worker -v app-data:/data python # Create or reuse a disk-backed named volume, then mount it msb run --name docker-demo \ --mount-named docker-data:/var/lib/docker:kind=disk,size=20G \ docker:dind # Share between sandboxes msb run --name writer -v shared:/data alpine -- sh -c "echo hello > /data/msg.txt" msb run --name reader -v shared:/data alpine -- cat /data/msg.txt ``` `--mount-named` accepts `kind=dir|disk`, disk `size`, and directory `quota`. Disk mounts require a size. Conflicting settings on an existing volume fail. Directory and bind mounts accept paired `uid` and `gid` guest-owner fallbacks. These do not change host ownership and cannot combine with `stat-virt=off` or disk mounts. The CLI distinguishes bind mounts from named volumes by looking for a `/` or `.` prefix. `./src:/app` is a bind mount (host path). `myvolume:/data` is a named volume. This matches Docker's convention. # Cloud Source: https://docs.microsandbox.dev/cloud/overview Run the same sandboxes on hosted infrastructure with an API key microsandbox cloud is in **private beta**, and currently requires you to explicitly [request access](https://dashboard.microsandbox.dev/signup). If you already have access, you can get your API key from the [dashboard](https://dashboard.microsandbox.dev/access/api-keys). microsandbox cloud runs your sandboxes on hosted infrastructure. The SDKs and the `msb` CLI are the same ones you use locally: the same builders, the same commands, the same code. Select the cloud backend and provide an API key; there is no daemon or separate client. ## Connect ```bash theme={null} export MSB_BACKEND=cloud export MSB_API_KEY="msb_..." msb context ``` `msb context` confirms that subsequent commands will run on cloud and shows what selected it without exposing the API key. For profiles, SDK selection, and precedence, see [Local or cloud](/operations/backends). ## Sandbox identity Looking up a sandbox by name selects the sandbox currently using that name. The returned object retains that sandbox's ID for lifecycle operations, commands, and file access. If the sandbox is deleted and its name reused, operations on an old object fail instead of reaching the replacement. Fetch the sandbox by name again to select the replacement; you do not need to manage IDs yourself. ## Same code, different backend Everything from the [quickstart](/getting-started/quickstart) works unchanged. With cloud selected and the API key exported, this creates a sandbox on cloud instead of your machine: ```typescript TypeScript theme={null} import { Sandbox } from "microsandbox"; await using sb = await Sandbox.builder("hello") .image("python") .memory(512) .create(); const output = await sb.exec("python", ["-c", "print('Hello from the cloud!')"]); console.log(output.stdout()); ``` ```rust Rust theme={null} use microsandbox::Sandbox; let sb = Sandbox::builder("hello") .image("python") .memory(512) .create() .await?; let output = sb.exec("python", ["-c", "print('Hello from the cloud!')"]).await?; println!("{}", output.stdout()?); sb.stop().await?; ``` ```python Python theme={null} from microsandbox import Sandbox sb = await Sandbox.create("hello", image="python", memory=512) output = await sb.exec("python", ["-c", "print('Hello from the cloud!')"]) print(output.stdout_text) await sb.stop() ``` ```go Go theme={null} sb, err := m.CreateSandbox(ctx, "hello", m.WithImage("python"), m.WithMemory(512), ) if err != nil { return err } defer sb.Stop(ctx) output, err := sb.Exec(ctx, "python", []string{"-c", "print('Hello from the cloud!')"}) fmt.Println(output.Stdout()) ``` ```ruby Ruby theme={null} require "microsandbox" Microsandbox::Sandbox.with("hello", image: "python", memory: 512) do |sb| output = sb.exec("python", ["-c", "print('Hello from the cloud!')"]) puts output.stdout end ``` ```bash CLI theme={null} msb run python -- python3 -c "print('Hello from the cloud!')" ``` Hardware virtualization support on your machine is not needed for cloud sandboxes; `msb doctor` checks apply to the local runtime only. ## What works on cloud Create, inspect, list, reconnect, start, stop, and remove sandboxes. Run buffered, streaming, and interactive commands, then move files in or out. Create managed volumes and access their files without starting a sandbox. Apply egress policy and hostname-scoped secrets from the same SDK surface. ## Compatibility The everyday workflow is shared across local and cloud: sandbox lifecycle, command execution, common guest-filesystem operations, network policy, secrets, SSH sessions, and managed storage. The differences below are the ones to plan for. Across the docs, no badge means a feature works everywhere. Exceptions use only three badges: **Local-only**, **Limited on cloud**, and **Cloud-only**. | Area | Cloud status | Difference or alternative | | - | - | - | | Sandbox lifecycle and execution | **Works everywhere** | Create, start, inspect, list, stop, remove, exec, shell, streaming, and interactive PTY workflows use the same SDK and CLI surface. | | Guest filesystem | **Limited on cloud** | Common path operations and host-to-guest copies work. Low-level open-handle operations are local-only. | | Managed volumes | **Limited on cloud** | Default and named directory volumes support lifecycle and filesystem access. Create a named volume before mounting it; disk-kind volumes and create-on-mount are local-only. | | Volume and host paths | **Limited on cloud** | Bind and disk-image source paths resolve against the organization's host volume, not the machine running the client. | | Network policy and secrets | **Works everywhere** | Egress policies and hostname-scoped secret substitution carry across backends. | | Custom networking | **Local-only** | Published ports, custom nameservers, interface overrides, rate limiters, TLS interception, and host-CA trust are not accepted by cloud create. | | Logs | **Limited on cloud** | SDK live-follow and `msb logs -f` work. Bounded or historical reads are local-only; persist followed output externally when retention matters. | | SSH | **Limited on cloud** | Native SDK sessions and `msb ssh` work. `msb ssh serve` is local-only; reusable SDK servers require explicit key material. | | Images | **Limited on cloud** | OCI image references and registry credentials work. Local cache commands, host-directory or disk-image roots, plain-HTTP registries, and custom registry CAs are local-only. | | Reconfiguration | **Local-only** | Recreate the sandbox with the new CPU, memory, mounts, or other settings instead of using `modify`. | | Snapshots | **Limited on cloud** | Capture disk snapshots from stopped persistent sandboxes and restore them into new sandboxes. Live capture, full checkpoints, forking, groups, and local artifact archives remain local-only. | | Resource metrics | **Local-only** | Instrument the workload with an external monitoring system. | | Process controls | **Limited on cloud** | Graceful stop plus maximum-duration and idle-timeout policies work. Force kill, drain, ping, and touch are local-only. | ## REST API The same key also authenticates the [REST API](/api-reference/overview) directly, so you can manage sandboxes, volumes, and usage over plain HTTPS without an SDK. Command execution, file transfer, and SSH ride the sandbox command channel, which the SDKs and CLI handle for you. ## What to know * **Local or cloud.** Cloud is explicit: set `MSB_BACKEND=cloud`, select a cloud profile, or choose it in code. See [Local or cloud](/operations/backends). * **Networking.** Cloud sandboxes get a platform-assigned hostname. SSH works through the same `msb ssh` and SDK SSH clients you use locally. * **Images.** Specify an OCI image when you create the sandbox; the cloud pulls it for you. * **Managed settings.** [Device policy](/enterprise/managed-configuration) applies to create requests and CLI/SDK SSH sessions. Unsupported create settings fail before the request is sent. Existing cloud sandboxes and the hosted SSH gateway keep their settings. * **Keys and billing.** API keys, usage, and invoices live in the [dashboard](https://dashboard.microsandbox.dev). ## Next steps The REST API behind the SDKs, authenticated with your API key. Force local, select in code, or switch with profiles. New to microsandbox? Start here; everything carries over. # Global configuration Source: https://docs.microsandbox.dev/configuration Configure microsandbox defaults for the CLI and SDKs using the shared config.json file. For guidance on choosing between global configuration, sandbox YAML, CLI arguments, and SDK inputs, start with [Configuration](/operations/configuration). microsandbox reads user configuration from `~/.microsandbox/config.json`, or `MSB_CONFIG_PATH` when set. All fields are optional. A missing file or empty JSON object adds no user overrides; defaults and managed settings still apply. Newly saved user files include `"version": 1`. An omitted version defaults to `1`; invalid or unsupported versions are rejected. In Rust, `GlobalConfigPatch::load()` reads saved user settings and `.save()` writes them without filling in defaults. Omitted fields remain omitted, and explicit clears are preserved. Unknown user fields are ignored on load and discarded on save. `GlobalConfig` holds resolved settings after layering; use `LocalBackend::config()` to read the effective backend configuration. ## Managed configuration Administrators can enforce these same fields using a protected `managed.json` file with the shape `{ "version": 1, "overrides": { ... } }`. Supplied managed values take precedence over ordinary user settings and CLI/SDK options. The user and managed files have independent schema versions, each defaulting to `1` when omitted. Managed values are not automatically saved into the user file. See [Managed deployment](/enterprise/managed-configuration) for deployment, precedence, clearing, and updates. This page remains the reference for individual fields and accepted values. ## Reference example Relative host paths stored in this file resolve from the file's directory, including `home`, `paths.*`, and `registries.ca_certs`. For example, `/etc/microsandbox/config.json` containing `"ca_certs": "./company.pem"` selects `/etc/microsandbox/company.pem`, regardless of the caller's working directory. This intentionally replaces the previous working-directory-relative interpretation. Use an absolute path to keep a location elsewhere. Programmatic SDK paths and environment defaults are captured relative to the caller's working directory when the backend is constructed. Guest paths, such as `sandbox_defaults.workdir`, are unaffected. ```json theme={null} { "home": "/custom/path/.microsandbox", "log_level": "info", "deployment_profile": "multi-tenant", "database": { "url": "sqlite:///tmp/msb.db", "max_connections": 10, "connect_timeout_secs": 30, "busy_timeout_secs": 30 }, "paths": { "msb": "/usr/local/bin/msb", "libkrunfw": "/usr/local/lib/libkrunfw.so", "agentd": "/usr/local/libexec/microsandbox/agentd", "cache": "/mnt/fast/msb-cache", "sandboxes": null, "volumes": null, "snapshots": null, "logs": null, "secrets": null }, "sandbox_defaults": { "cpus": 2, "memory_mib": 1024, "cpu_placement": "auto", "placement_profile": "latency", "thp": "madvise", "oci": { "root_disk": { "kind": "flat", "size_mib": 8192, "clone": "auto" } }, "shell": "/bin/bash", "workdir": "/app" }, "runtime": { "placement_profiles": { "latency": { "numa": { "mode": "prefer_single" }, "memory": { "mode": "follow_cpu" } } }, "block_writeback": { "mode": "auto" } }, "registries": { "ca_certs": "/path/to/corporate-ca.pem", "hosts": { "ghcr.io": { "auth": { "username": "octocat", "store": "keyring" } }, "registry.example.com": { "insecure": true, "auth": { "username": "deploy", "password_env": "REGISTRY_TOKEN" } }, "docker.io": { "auth": { "username": "user", "secret_name": "dockerhub-token" } } } }, "ssh": { "inactivity_timeout_secs": 600 }, "metrics": { "capacity": 4096 }, "snapshots": { "max_filesystem_state_mib": 4 }, "active_profile": "prod", "profiles": { "prod": { "backend": "cloud", "api_key_ref": "env:MSB_API_KEY" }, "local": { "backend": "local" } } } ``` ## Top-level fields | Field | Default | Description | | - | - | - | | `home` | `~/.microsandbox` | Root directory for all microsandbox data | | `log_level` | `null` (silent) | Log level for sandbox processes: `error`, `warn`, `info`, `debug`, `trace` | | `deployment_profile` | `null` | Authoritative local host-runtime isolation profile: `single-tenant` or `multi-tenant` | | `database` | [reference](#database) | Database connection settings | | `paths` | [reference](#paths) | Path overrides for binaries and directories | | `sandbox_defaults` | [reference](#sandbox_defaults) | Defaults applied to new sandboxes, subject to backend support | | `runtime` | [reference](#runtime) | Host runtime performance policy | | `registries` | [reference](#registries) | Container registry authentication | | `ssh` | [reference](#ssh) | Host-side SSH session defaults | | `metrics` | [reference](#metrics) | Live metrics shared-memory registry settings | | `snapshots` | [reference](#snapshots) | Full snapshot capture and restore limits | | `active_profile` | `null` | Default [backend profile](#profiles) name | | `profiles` | [reference](#profiles) | Named [backend profiles](/operations/backends#profiles) | ## `deployment_profile` Local-only Set `deployment_profile` when the local host must enforce one deployment policy for every sandbox: ```json theme={null} { "deployment_profile": "multi-tenant" } ``` `single-tenant` preserves the network configuration requested by each sandbox. `multi-tenant` applies the host-runtime isolation floor for shared infrastructure. The configured value is authoritative on create and restart, so a per-sandbox CLI or SDK option cannot weaken or replace it. A programmatic `LocalBackendBuilder::deployment_profile()` override takes precedence over the file. When the field is absent or `null`, each sandbox selects its own profile and defaults to `single-tenant`. The parser also accepts the internal wire spellings `single_tenant` and `multi_tenant` for compatibility, but the kebab-case values above are canonical in this human-edited file. ## `database` Local-only | Field | Default | Description | | - | - | - | | `url` | `null` | Database URL. Uses SQLite under `home` when null | | `max_connections` | `5` | Maximum connection pool size | | `connect_timeout_secs` | `30` | Timeout when acquiring a database connection from the pool | | `busy_timeout_secs` | `30` | SQLite busy timeout before a contended write surfaces as an error | ## `paths` Local-only All path fields are optional. Runtime pairs resolve from environment overrides, SDK-provided paths, explicit configuration, then the install under `home`. Other unset paths resolve relative to `home`; runtime resolution does not search `PATH` or debug build directories. On Windows, the default `home` is `%USERPROFILE%\.microsandbox`. JSON strings can use escaped backslashes such as `"C:\\Users\\you\\.microsandbox\\lib\\libkrunfw.dll"` or forward slashes such as `"C:/Users/you/.microsandbox/lib/libkrunfw.dll"`. | Field | Default | Description | | - | - | - | | `msb` | `{home}/bin/msb` | `msb` binary. Configure a matching `libkrunfw` path; when omitted, resolution can use a library adjacent to this executable. An incomplete pair fails closed. | | `libkrunfw` | `{home}/lib/libkrunfw` | Matching libkrunfw shared library (`.so` on Linux, `.dylib` on macOS, `.dll` on Windows). Set this together with `msb`. | | `agentd` | embedded when enabled | Linux guest Agentd executable. Normal release builds embed it in `msb`; custom builds without `embed-binaries` must provide this field or `MSB_AGENTD_PATH`. The environment variable takes precedence, and an explicitly configured missing or invalid file fails closed. | | `cache` | `{home}/cache` | Image layer cache | | `sandboxes` | `{home}/sandboxes` | Per-sandbox state | | `volumes` | `{home}/volumes` | Named volumes | | `snapshots` | `{home}/snapshots` | Snapshot artifacts | | `logs` | `{home}/logs` | Sandbox logs | | `secrets` | `{home}/secrets` | Secrets. Registry secrets live under `secrets/registries/` | Runtime path settings are captured during local backend construction, with managed paths taking precedence. Existing backend handles keep their settings until replaced. ### Rust SDK path helpers Rust callers can inspect the active config and resolve runtime paths with the same precedence used by sandbox startup: ```rust theme={null} let cfg = microsandbox::config::config()?; let runtime = microsandbox::setup::resolve_runtime(&cfg)?; let msb = &runtime.msb_path; let libkrunfw = &runtime.libkrunfw_path; ``` When your code owns an explicit local backend, prefer the backend-owned config: ```rust theme={null} use microsandbox::LocalBackend; let backend = LocalBackend::builder() .home("/tmp/msb-home") .build() .await?; let cfg = backend.config(); let runtime = microsandbox::setup::resolve_runtime(&cfg)?; ``` `LocalBackend` has two plain constructors alongside the builder. `LocalBackend::lazy()?` is synchronous and defers opening (and migrating) the local sandbox database until the first operation; it is what backend resolution uses when no backend is set explicitly. `LocalBackend::new().await?` opens the database up front, so startup fails fast if the database is unusable. All constructors read, layer, and validate global configuration before returning a backend; only database setup is lazy. Proxy settings are validated after sandbox options and managed overrides are composed, before network use. `LocalBackendBuilder::build_lazy()` now returns `Result`. It replaces `try_build_lazy()`, and `LocalBackend` no longer implements `Default`; use `LocalBackend::lazy()?` instead. For a long-lived process, construct a new backend to pick up configuration changes. Installing it with `set_default_backend` affects future operations; existing sandbox and volume handles retain their original backend. Construct the replacement successfully before installing it. ## `ssh` | Field | Default | Description | | - | - | - | | `inactivity_timeout_secs` | `600` | Disconnect an SSH session after this many seconds without SSH traffic. Set to `0` to disable. | The timeout applies to host-side SSH sessions created by `msb ssh`, `msb ssh serve`, and the SDK, for both local and cloud sandboxes. SSH traffic resets the timer. This setting is separate from a sandbox lifecycle idle timeout: disconnecting SSH does not stop the sandbox, and sandbox activity policy does not change the SSH timeout. Explicit CLI or SDK options override the user-configured value; a managed timeout takes precedence over both. The setting is resolved when a client or server endpoint is prepared using the backend's retained configuration, so file changes do not alter existing connections. Programmatic local backends can override the persisted value with `LocalBackendBuilder::ssh_inactivity_timeout_secs()`. ## `sandbox_defaults` Limited on cloud Defaults applied to sandboxes unless overridden per-sandbox. Explicit CLI or SDK options win over `config.json`, and managed overrides take precedence over both. microsandbox resolves the effective values before creating a local sandbox or sending a cloud create request. Cloud creation rejects sandbox options it cannot represent. File changes apply after constructing a new backend or starting a new CLI invocation; they do not rewrite existing sandboxes. Rust applications can use [`SandboxBuilder::overlay`](/sdk/rust/sandbox#sandbox-overlay) to add sparse per-sandbox values. Local creation resolves built-in defaults \< image defaults \< `config.json` \< CLI/SDK patches \< managed overrides after image metadata is available. Cloud creation applies user settings, request options, and managed overrides on the client; the cloud worker resolves image metadata. For local `workdir`, omission inherits the lower layer and explicit `null` clears it, including an image working directory. A concrete Rust `SandboxConfig` with `workdir: None` is treated as omitted. Local CPU and memory maxima remain explicit when supplied; otherwise they follow the final size. Cloud supports no separate hotplug maximum: a supplied maximum equal to the requested size follows the final size. A maximum that differs from the final size is rejected. For workload effects, host requirements, filesystem expectations, and verification steps for these settings, see [Performance](/sandboxes/optimization). | Field | Default | Description | | - | - | - | | `cpus` | `1` | Number of vCPUs | | `memory_mib` | `512` | Guest memory in MiB | | `cpu_placement` | `"inherit"` | Host vCPU placement: `inherit`, `auto`, `spread`, or `compact` | | `placement_profile` | `null` | Name of a host-defined entry in `runtime.placement_profiles` | | `thp` | `"madvise"` | Guest transparent huge-page policy: `always`, `madvise`, or `never` | | `oci` | [reference](#sandbox_defaults-oci) | Defaults for OCI-rooted sandboxes | | `shell` | `"/bin/sh"` | Shell for interactive sessions and scripts | | `workdir` | `null` | Working directory inside the sandbox | | `outbound_proxy` | `null` | Default outbound SOCKS4/SOCKS5 proxy for local sandboxes. Uses the existing proxy object with `protocol`, `address` (`IP:port`), and optional authentication. See [managed proxy configuration](/enterprise/corporate-networking#route-sandbox-traffic). | | `metrics_sample_interval_ms` | `1000` | Runtime metrics sampling interval in milliseconds. Set to `0` to disable sampling. | | `disable_metrics_sample` | `false` | Force-disable metrics sampling regardless of `metrics_sample_interval_ms`. | An ordinary `outbound_proxy` default can be overridden per sandbox. A managed value takes precedence over CLI/SDK proxy options; managed `null` clears them. The whole proxy object is replaced, including credentials. SOCKS4 accepts an optional `user_id`; SOCKS5 accepts `credentials` containing `username` and `password: { "kind": "env", "var": "PROXY_PASSWORD" }`. Passwords are resolved at sandbox startup. Proxy defaults do not enable disabled networking or route host downloads. Cloud creation fails if the final configuration contains a proxy, including one supplied by managed policy. ### `sandbox_defaults.oci` Defaults applied only when the sandbox rootfs is an OCI image. User OCI defaults apply to local creation. Managed root-disk settings also apply to cloud create requests, which accept only `kind: "managed"`. | Field | Default | Description | | - | - | - | | `root_disk` | `null` | Default OCI root disk using the same tagged shape as the SDK: `managed`, `tmpfs`, or `flat`. A missing value preserves the managed layered root. User-owned `disk-image` defaults are rejected because they would share one writable image across sandboxes. | | `upper_size_mib` | `null` | Deprecated managed-layered size shorthand. When both this field and `root_disk` are absent, the resolved managed size is 4096 MiB. | `root_disk` and `upper_size_mib` are mutually exclusive. For a portable flat default, use `clone: "auto"`; it attempts a native reflink and safely falls back to a sparse copy. Use `clone: "reflink"` only when failure is preferable to copying on a host filesystem without reflink support. When the root-disk default is flat, plain `msb pull IMAGE` also prepares the reusable flat artifact. An explicit `msb pull IMAGE --materialize layered|flat|all` always wins. ## `runtime` Local-only | Field | Default | Description | | - | - | - | | `block_writeback` | `{ "mode": "auto" }` | Buffered host writeback containment and live pressure sharing on Linux. Pool pressure never rejects sandbox creation; unconfigured `auto` is a no-op on other hosts. | | `placement_profiles` | `{}` | Host-owned named CPU and NUMA placement profiles selectable by sandboxes | ### `runtime.placement_profiles` Placement profiles let an operator define safe host topology policy once while callers select it by name. `numa.mode` is `prefer_single`, `strict_single`, or `inherit`; `memory.mode` is `follow_cpu` or `inherit`. This release does not enable multi-node guest placement. `prefer_single` falls back to inherited host NUMA behavior when one node cannot fit. `strict_single` fails clearly because it is an explicit guarantee. `follow_cpu` requires managed CPU placement (`auto`, `spread`, or `compact`). Linux prefers the selected node for ordinary profiles and allows memory to spill elsewhere under pressure; `strict_single` uses a required binding instead. If CPUs span nodes, capacity is already insufficient, or the kernel rejects a best-effort affinity or memory-policy syscall, an ordinary profile starts with inherited memory placement. Windows keeps ordinary memory inherited because its preferred-node allocation cannot be undone if a later vCPU affinity attempt falls back; `strict_single` can still request required preferred-node allocation. Windows checks current boot-time availability, but does not expose equivalent per-node total capacity for a hard future-growth promise. macOS inherits ordinary CPU and memory scheduling for non-strict profiles because it has no equivalent hard-affinity API. ### `runtime.block_writeback` | Field | Modes | Default | Description | | - | - | - | - | | `mode` | all | `"auto"` | `auto` gives each eligible disk a measured 1536 MiB maximum and shares the aggregate pool when the host is busy, `fixed` requires an explicit maximum, and `off` disables both the VMM bound and host-global pressure coordination. | | `per_disk_mib` | `fixed` | required | Explicit maximum for each eligible writable raw disk. The boot-time maximum is at least 128 MiB; the live fair share may fall below it under aggregate pressure. This field is rejected in `auto` and `off` modes. | | `pool_mib` | `auto`, `fixed` | `null` | Optional aggregate dirty-credit pressure-pool override. `null` derives the pool as the lower of 10% of physical RAM and a conservative estimate of Linux's dirty-background threshold, using the exact byte threshold when configured or the ratio applied to current `MemAvailable`. This field is rejected in `off` mode. | Use a fixed policy only when representative measurements justify a different per-disk window: ```json theme={null} { "runtime": { "block_writeback": { "mode": "fixed", "per_disk_mib": 2048, "pool_mib": 12288 } } } ``` `pool_mib` is a live pressure budget, not eagerly allocated RAM. Every eligible writable disk in the same `MSB_HOME` receives a weighted max-min fair share. Disks with a smaller configured maximum keep that smaller value, and the remaining pool is divided equally across the rest. Creating another sandbox never fails merely because this pool is full. Existing VMMs observe membership changes within 250 ms. If a disk already owns more dirty data than its new share, libkrun retires accounted ranges and pauses later writes until it converges below the target. A guest write already reserved before the target changed completes safely. `fixed` and an explicitly pooled `auto` policy are unsupported on other hosts. See the [performance guide](/sandboxes/optimization) for choosing and measuring runtime settings. ## `registries` Local-only | Field | Default | Description | | - | - | - | | `ca_certs` | `null` | Path to a PEM file with additional CA root certificates trusted for registry pulls | | `hosts` | `{}` | Per-registry settings keyed by registry hostname | ### `registries.hosts` A map of registry hostnames to settings. Each host entry can mark the registry as insecure (plain HTTP) and can include an `auth` entry. Each auth entry specifies a username and exactly **one** credential source. ```json theme={null} { "registries": { "hosts": { "ghcr.io": { "auth": { "username": "octocat", "store": "keyring" } }, "localhost:5050": { "insecure": true, "auth": { "username": "dev", "password_env": "LOCAL_REGISTRY_TOKEN" } } } } } ``` #### Host entry fields | Field | Required | Description | | - | - | - | | `insecure` | No | Use plain HTTP instead of HTTPS for this registry | | `auth` | No | Authentication entry for this registry | #### Auth entry fields | Field | Required | Description | | - | - | - | | `username` | Yes | Registry username | | `store` | No | Credential store. Only `"keyring"` is supported (macOS Keychain, Windows Credential Manager, Linux Secret Service) | | `password_env` | No | Environment variable containing the password or token | | `secret_name` | No | Filename under `{home}/secrets/registries/` containing the password or token | Exactly one of `store`, `password_env`, or `secret_name` must be set per entry. Setting none or more than one is an error. ### Auth resolution order Managed registry hosts merge by field. Setting `insecure: false` enforces TLS while preserving employee credentials. Omitted `auth` keeps the normal credential lookup and CLI/SDK credentials; explicit `auth: null` forces anonymous access. A managed `auth` object replaces credentials, including explicit CLI/SDK credentials. A managed `registries.ca_certs` path replaces user and per-call certificates; `null` clears them. Without a managed certificate setting, per-call certificates append to user certificates. For local pulls without managed `auth`, microsandbox resolves credentials in this order, including when a managed host entry only sets TLS options: 1. **Explicit SDK auth** via `.registry(|r| r.auth(...))` on the sandbox builder 2. **OS keyring** entries created by `msb registry login` 3. **Config file** `registries.hosts..auth` entries in `config.json` 4. **Docker config** `~/.docker/config.json` credential helpers 5. **Anonymous** (no authentication) ## `metrics` Local-only | Field | Default | Description | | - | - | - | | `capacity` | `0` | Number of slots reserved in the live metrics shared-memory registry. `0` uses the built-in default. Stop all sandboxes for the same home before changing this value. | ## `snapshots` | Field | Default | Description | | - | - | - | | `max_filesystem_state_mib` | `4` | Largest virtio-fs backend state, in MiB, that one filesystem device can carry through a full snapshot. Valid values are `1` through `4095`. | This limit applies per filesystem device during capture, verification, export, import, restore, and live forks. * **After changing it:** restart running sandboxes to update their capture limit. Host snapshot checks use the new limit immediately, so lowering it can reject captures from sandboxes still using a larger limit. * **When reading snapshots:** allow enough space for each device's saved state. The reader does not need to match the capture host's maximum. A smaller limit rejects oversized state before making changes. * **Before raising it:** consider memory use, especially when restoring imported snapshots. Raise it only for snapshots you trust. ## `profiles` Named backend profiles keyed by profile name; `active_profile` selects the default. How profiles participate in local or cloud selection, including the full precedence order, is documented in [Local or cloud](/operations/backends). | Field | Default | Description | | - | - | - | | `backend` | required | `local` or `cloud` | | `api_key_ref` | none | Credential reference; required for `cloud` profiles | | `url` | `https://api.microsandbox.dev` | Cloud endpoint override for development, self-hosted, or on-prem control planes | Supported credential references for `api_key_ref`: | Prefix | Description | | - | - | | `env:` | Read the API key from an environment variable | | `inline:` | Store the API key directly in `config.json`; use only for development or CI | # Enterprise deployment Source: https://docs.microsandbox.dev/enterprise Choose a deployment approach for employee devices or your own infrastructure Use microsandbox on employee devices or in your own infrastructure. Choose the deployment approach that fits your workloads and operational requirements. ## Choose your deployment | Deployment | Purpose | Next step | | - | - | - | | Employee devices | Standardize local development and team settings | [Rollout guides](#roll-out-to-employee-devices) | | Runtime on your infrastructure | Run sandboxes on your servers or clusters | [Discuss your deployment](/enterprise/contact) | | Private cloud deployment | Run the microsandbox cloud platform in your infrastructure | [Discuss requirements](/enterprise/contact) | For our hosted service, see [microsandbox Cloud](/cloud/overview). ## Roll out to employee devices Start with one working installation, connect it to company services, then apply policy and roll it out to a pilot group. | Step | Outcome | | - | - | | [Prepare your environment](/enterprise/prepare-environment) | Approved SDKs, runtime files, and images work on the target devices, including offline installations. | | [Configure company networking](/enterprise/corporate-networking) | Sandboxes can reach approved services through company routing, DNS, and certificate trust. | | [Enforce team settings](/enterprise/managed-configuration) | A protected policy defines which supported settings employees cannot override. | | [Deploy and verify](/enterprise/deploy-and-verify) | A tested pilot, repeatable device deployment, and an update and rollback process. | ### Deployment responsibilities | microsandbox provides | Your organization manages | | - | - | | Local sandbox isolation and network controls | Device security, host permissions, and approved workloads | | Managed overrides for supported CLI and SDK settings | Policy distribution, file protection, and supported client versions | | Runtime and image installation tools | Package approval, distribution, and updates | | Configuration for company network access | VPN/proxy enrollment, credentials, DNS, and corporate certificates | Managed settings apply through supported CLI and SDK clients. They are not a replacement for device security: local administrators can remove policy or replace the runtime. These guides focus on local sandboxes on company-managed devices. Some managed settings also apply to outgoing cloud requests, as described in [Enforce team settings](/enterprise/managed-configuration). They do not reconfigure the cloud service. ## Discuss your deployment Planning a runtime rollout or private cloud deployment? [Contact our team](/enterprise/contact) with a short description of your workloads and deployment needs. # Talk to the microsandbox team Source: https://docs.microsandbox.dev/enterprise/contact Let’s plan your microsandbox deployment From a team rollout to a private cloud, talk with us about the architecture, networking, and operational requirements that matter to you. You don’t need a finished plan to start a conversation. Prefer email? Reach us at [sales@microsandbox.dev](mailto:sales@microsandbox.dev).