# How Microsandbox Handles Inter-Process Communication: 3 IPC Mechanisms Explained

> Discover how Microsandbox uses three IPC mechanisms Virtio-vsock Agent Relay and Lifecycle Guard for secure inter-process communication between hosts guests and SDK clients.

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

---

**Microsandbox implements three complementary inter-process communication (IPC) mechanisms—Virtio-vsock for guest-host communication, an Agent Relay for SDK client connections, and a Lifecycle Guard for exclusive sandbox ownership—that together enable secure, isolated communication between host processes, sandboxed guests, and SDK clients.**

This article examines the IPC architecture in [superradcompany/microsandbox](https://github.com/superradcompany/microsandbox), analyzing how the runtime enables communication across isolation boundaries while maintaining security guarantees.

## Virtio-vsock: Guest-Host Communication

Microsandbox uses **Virtio-vsock** to expose host services to sandboxed guests through emulated vsock devices. This mechanism connects the guest's CID address space to host-side IPC endpoints.

### Vsock Specification

The vsock configuration originates in the sandbox specification defined in [`packages/microsandbox-types/rust/lib/domain.rs`](https://github.com/superradcompany/microsandbox/blob/main/packages/microsandbox-types/rust/lib/domain.rs):

```rust
pub struct VsockSpec {
    /// One host local‑IPC endpoint exposed on a host‑CID vsock port.
    pub routes: Vec<VsockRouteSpec>,
}

```

Each `VsockRouteSpec` defines a mapping between a host IPC endpoint and a guest-visible vsock port. The runtime supports both **stream** (TCP-like) and **datagram** (UDP-like) semantics.

### Host-Side Back-Ends

During VM startup in [`crates/runtime/lib/vm.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/vm.rs), vsock routes become concrete back-end implementations:

```rust
use microsandbox_vsock::{UnixDatagramPortBackend, UnixStreamPortBackend};

let vsock_backends = config.spec.vsock.routes.clone();

```

The back-end implementations handle platform-specific transport:

- **Linux/macOS**: Unix domain sockets (`UnixStreamPortBackend`, `UnixDatagramPortBackend`)
- **Windows**: Named pipes (equivalent abstractions in [`crates/vsock/lib/stream.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/vsock/lib/stream.rs) and [`crates/vsock/lib/dgram.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/vsock/lib/dgram.rs))

Guests connect using standard vsock APIs, unaware of the host's actual transport implementation.

## Agent Relay: SDK Client to Guest Communication

The **Agent Relay** bridges SDK clients with the guest's internal agent (`agentd`). This local IPC mechanism enables programmatic control of sandboxed workloads.

### Connection Establishment

The relay listens on per-sandbox sockets created in [`crates/runtime/lib/relay.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/relay.rs):

```rust
// AgentListener::bind creates the socket with proper cleanup
let listener = AgentListener::bind(&socket_path).await?;

```

The implementation handles stale socket files and ensures parent directory creation at lines 49-66.

### Client Isolation via Correlation IDs

Each connecting client receives an exclusive **correlation-ID range** to isolate protocol frames:

```rust
// Handshake assigns ID range to client
let mut handshake = Vec::with_capacity(8 + ready_frame.len());
handshake.extend_from_slice(&id_start.to_be_bytes());
handshake.extend_from_slice(&id_end_exclusive.to_be_bytes());
handshake.extend_from_slice(&ready_frame);
writer_half.write_all(&handshake).await?;

```

The slot allocation uses `AGENT_RELAY_ID_RANGE_STEP` to partition the 64-bit ID space, ensuring responses route to correct clients even with concurrent connections.

### Frame Forwarding Architecture

The relay operates on raw binary frames without parsing overhead:

- **TX path**: Client → `tx_ring` → guest agent
- **RX path**: Guest agent → `rx_ring` → client

Connection cleanup includes `SIGKILL` delivery to active exec sessions when clients disconnect, implemented in the session management logic.

### Legacy Compatibility

The relay maintains backward compatibility through symbolic links:

- `publish_legacy_agent_link` — canonical `agent.sock` access
- `publish_legacy_control_link` — legacy `control.sock` routing

New clients use the unified socket layout while existing code continues functioning.

## Lifecycle Guard: Exclusive Sandbox Ownership

The **SandboxLifecycleGuard** prevents race conditions when multiple host processes attempt to launch identical sandbox configurations.

### Advisory Locking Implementation

In [`crates/runtime/lib/ipc.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/ipc.rs), the guard acquires an exclusive `flock`:

```rust
let file = OpenOptions::new()
    .create(true)
    .read(true)
    .write(true)
    .open(&path)?;
let operation = libc::LOCK_EX | if nonblocking { libc::LOCK_NB } else { 0 };
if unsafe { libc::flock(file.as_raw_fd(), operation) } == 0 {
    Ok(Some(SandboxLifecycleGuard { file }))
}

```

Lock files reside at `locks/<hash>.lock` relative to the run directory.

### Lock Persistence Across Processes

The guard supports duplication into sandbox child processes. This ensures the lock persists after the launcher exits, preventing premature sandbox termination due to lock release.

## Using Microsandbox IPC in Practice

### Rust SDK: Configuring Vsock Routes

```rust
use microsandbox_sdk::sandbox::SandboxBuilder;

let sandbox = SandboxBuilder::new()
    .vsock("/run/host-api.sock", 5000)  // Unix socket exposed on vsock port 5000
    .vsock_dgram("/run/metrics.sock", 5001)  // Datagram route
    .build()
    .await?;

```

The `vsock` and `vsock_dgram` methods in [`sdk/rust/lib/sandbox/builder.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/builder.rs) (lines 803-820) populate the `VsockRouteSpec` vector.

### Python SDK: Connecting to Running Sandboxes

```python
import microsandbox

sandbox = microsandbox.Sandbox(name="demo")
client = sandbox.connect()      # Connects via agent.sock

result = client.exec("echo hello")
print(result.stdout)

```

Python arguments parse through [`sdk/python/src/helpers.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/python/src/helpers.rs) before forwarding to the Rust builder. The connection routes through the Agent Relay.

### Manual Socket Inspection

```bash

# Discover socket path

cat /tmp/msb/run/sandboxes/87eba76e7f3164534045ba92/agent.sock

# Raw binary communication

socat - UNIX-CONNECT:/tmp/msb/run/sandboxes/87eba76e7f3164534045ba92/agent.sock

```

Socket paths generate via `sandbox_socket_paths` in [`crates/runtime/lib/ipc.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/ipc.rs) (lines 59-76), incorporating sandbox hashes for isolation.

## Key Implementation Files

| Path | Responsibility |
|------|----------------|
| [`crates/runtime/lib/ipc.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/ipc.rs) | Socket path generation, lifecycle lock acquisition, socket cleanup |
| [`crates/runtime/lib/relay.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/runtime/lib/relay.rs) | AgentRelay implementation: handshakes, ID ranges, frame forwarding |
| [`crates/vsock/lib/stream.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/vsock/lib/stream.rs) | Unix stream socket vsock back-end |
| [`crates/vsock/lib/dgram.rs`](https://github.com/superradcompany/microsandbox/blob/main/crates/vsock/lib/dgram.rs) | Unix datagram socket vsock back-end |
| [`packages/microsandbox-types/rust/lib/domain.rs`](https://github.com/superradcompany/microsandbox/blob/main/packages/microsandbox-types/rust/lib/domain.rs) | `VsockSpec`, `VsockRouteSpec` definitions |
| [`sdk/rust/lib/sandbox/builder.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/rust/lib/sandbox/builder.rs) | Rust SDK vsock configuration methods |
| [`sdk/python/src/helpers.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/python/src/helpers.rs) | Python SDK argument parsing |
| [`sdk/node-ts/native/sandbox_builder.rs`](https://github.com/superradcompany/microsandbox/blob/main/sdk/node-ts/native/sandbox_builder.rs) | TypeScript/Node SDK bindings |

All IPC artifacts reside under the sandbox's run directory (`$MSB_HOME/run`), enabling complete cleanup on termination.

## Summary

- **Virtio-vsock** provides guest-to-host connectivity through emulated devices backed by Unix sockets or named pipes, configured via `VsockRouteSpec` entries
- **Agent Relay** manages SDK client connections using correlation-ID isolation and raw frame forwarding over `agent.sock` / `control.sock`
- **Lifecycle Guard** ensures single-owner semantics through advisory file locking that survives process boundaries
- All three mechanisms compose to enable secure, isolated communication without sacrificing performance or compatibility

## Frequently Asked Questions

### How does microsandbox prevent multiple SDK clients from interfering with each other?

The Agent Relay assigns each client an exclusive correlation-ID range during the initial handshake. This range determines which protocol frames belong to which client, ensuring response isolation even with concurrent connections to the same sandbox.

### Can vsock routes use different transport types on Linux versus Windows?

Yes. The `VsockRouteSpec` configuration is transport-agnostic; the runtime selects appropriate back-ends automatically. Linux and macOS use `UnixStreamPortBackend` or `UnixDatagramPortBackend`, while Windows uses equivalent named pipe implementations—guest code remains identical across platforms.

### What happens if a client disconnects while running a command in the sandbox?

The Agent Relay detects connection loss and delivers `SIGKILL` to any active exec sessions associated with that client's correlation-ID range. This prevents orphaned processes and ensures resource cleanup.

### Is the lifecycle guard required for all sandbox operations?

The guard is mandatory for sandbox launch operations to prevent duplicate initialization. The non-blocking flag (`LOCK_NB`) enables fast-fail when a sandbox is already running, while the duplicatable lock file descriptor allows the guard to persist across `fork`/`exec` boundaries.