Skip to main content
The events API is for structured communication between host and guest beyond stdin/stdout. The host can subscribe to named events from the guest and emit events back, all through the same channel used by exec. On the guest side, processes just write JSON to /run/agent.sock, which is a standard Unix domain socket. No special library needed. Any language that can open a socket and write a newline-delimited JSON message will work.

Receive events from guest

Subscribe to named events emitted by guest processes. The callback fires each time a matching event arrives.
use microsandbox::{Sandbox, EventData};
use serde::Deserialize;

let sb = Sandbox::get("worker").await?.start().await?;

let _sub = sb.on_event("task.progress", |event: EventData| {
    #[derive(Deserialize)]
    struct Progress { percent: u32, message: String }

    if let Some(data) = event.data {
        if let Ok(p) = data.deserialized::<Progress>() {
            println!("[{}%] {}", p.percent, p.message);
        }
    }
});

Send events to guest

Emit a named event with typed data into the guest. Any process listening on the agent socket receives it.
use microsandbox::Sandbox;
use serde::Serialize;

#[derive(Serialize)]
struct TaskConfig { input_file: String, output_dir: String }

sb.emit("task.start", TaskConfig {
    input_file: "/data/input.txt".into(),
    output_dir: "/data/output".into(),
}).await?;

Guest-side emitting

Inside the guest, any process can emit events by writing JSON to the Unix domain socket at /run/agent.sock. No SDK required.
# Inside the guest, plain Python, no SDK
import json, socket

sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/run/agent.sock")
sock.sendall(json.dumps({
    "event": "task.progress",
    "data": {"percent": 50, "message": "Halfway done"},
}).encode() + b"\n")
sock.close()
The host subscription registered with on_event("task.progress", ...) receives this message automatically.