Transport

Chronicle replication uses length-prefixed bincode-serialized messages over:
  • Unix domain sockets: For local agent-sandbox communication
  • WebSocket: For remote sandboxes (E2B microVMs)

Framing

[4 bytes: payload length (LE u32)] [bincode payload]
Maximum message size: 100MB (to prevent DoS).

WireMessage Enum

All replication messages are variants of the WireMessage enum:
#[derive(Serialize, Deserialize)]
enum WireMessage {
    /// Agent → Sandbox: File change notification
    Notification {
        sequence: u64,
        filepath: String,
        content_hash: String,
        size: u64,
        permissions: i64,
        is_deletion: bool,
        inline_content: Option<Vec<u8>>,  // Content for small files (<4KB)
    },

    /// Agent → Sandbox: Heartbeat with current state
    Heartbeat {
        agent_sequence: u64,
        agent_iteration: i64,
    },

    /// Sandbox → Agent: Write-back batch
    WriteBack {
        sandbox_id: String,
        entries: Vec<WriteBackEntry>,
    },

    /// Agent → Sandbox: Write-back results
    WriteBackResult {
        accepted: Vec<(u64, i64)>,    // (local_seq, master_iteration)
        rejected: Vec<(u64, String)>, // (local_seq, reason)
    },

    /// Sandbox → Agent: Barrier request
    BarrierRequest { sequence: u64 },

    /// Agent → Sandbox: Barrier confirmation
    BarrierConfirmation { satisfied: bool, current_sequence: u64 },

    /// Sandbox → Agent: Acknowledge processed up to
    Ack { up_to_sequence: u64 },

    /// Sandbox → Agent: Request content by hash
    ContentFetchRequest { content_hash: String },

    /// Agent → Sandbox: Content delivery
    ContentFetchResponse {
        content_hash: String,
        content: Vec<u8>,
        size: u64,
        chunk_manifest: Option<String>,  // JSON ChunkManifest for large files
    },

    /// Agent → Sandbox: Content not found
    ContentNotFound { content_hash: String },

    /// Sandbox → Agent: Request catchup from sequence
    CatchupRequest {
        sandbox_id: String,
        since_sequence: u64,
    },

    /// Agent → Sandbox: Full resync required
    FullResyncRequired {
        reason: String,
        current_sequence: u64,
    },
}

WriteBackEntry

struct WriteBackEntry {
    local_seq: u64,           // Local sequence (for ACK correlation)
    filepath: String,         // File path being modified
    operation: WriteOperation, // Write, Delete, Rename, Chmod
    content_hash: Option<String>,
    content_bytes: Option<Vec<u8>>,
    size: i64,
    permissions: i64,
    is_deletion: bool,
    master_rowid_seen: i64,   // Causal dependency
}

enum WriteOperation {
    Write,
    Delete,
    Rename { new_path: String },
    Chmod,
}

Sequence Numbers

The protocol uses monotonically increasing sequence numbers:
  • Agent sequence: Increments on each file change notification
  • Sandbox ACK: Confirms processing up to a sequence number
  • Heartbeat: Carries current agent sequence for gap detection

WebSocket Transport

For E2B sandboxes where Unix sockets aren’t available:
Agent: --ws-listen 0.0.0.0:3002
Sandbox: --ws-connect ws://agent-host:3002
The WebSocket transport wraps the same WireMessage format — the protocol is transport-agnostic.