# Guest Wire Protocol Specification

Binary framing, packet opcodes, big-endian encoding, and stream multiplexing over virtio-vsock.

HTML: https://dynocap.dev/docs/reference/guest-wire-protocol

The host daemon communicates with the in-guest `dynocap-agent` over a point-to-point **virtio-vsock** connection on guest port `5252`.

The protocol is binary, big-endian, and synchronous with frame length prefixes.

---

## Wire Framing

Every frame transmitted over vsock consists of a 4-byte length header followed by the message payload:

```
+---------------------------+-----------------------------------+
| Frame Length (UInt32, BE) | Message Payload (1..1,048,576 B)  |
| 4 bytes                   | [Opcode (1B)] + [Body]            |
+---------------------------+-----------------------------------+
```

- **Byte Order:** Network byte order (Big-Endian).
- **Maximum Frame Size:** 1 MiB (`1,048,576` bytes).
- **Maximum Chunk:** 256 KiB (`262,144` bytes) for streamed I/O.
- **Port:** Guest vsock port `5252`.
- **Authentication:** None (vsock exists purely within the hypervisor memory boundary; host socket is mode `0600`).

---

## Message Opcodes

| Opcode | Hex    | Direction    | Name        | Description                                             |
| :----- | :----- | :----------- | :---------- | :------------------------------------------------------ |
| `1`    | `0x01` | Guest → Host | `HELLO`     | Sent immediately after guest agent starts up.           |
| `2`    | `0x02` | Host → Guest | `EXEC`      | Start a standard non-interactive process.               |
| `7`    | `0x07` | Host → Guest | `EXEC_TTY`  | Start a process allocated on a pseudo-terminal (PTY).   |
| `3`    | `0x03` | Host → Guest | `STDIN`     | Chunks of stdin data forwarded to process.              |
| `4`    | `0x04` | Host → Guest | `STDIN_EOF` | Closes stdin for the specified execution.               |
| `5`    | `0x05` | Host → Guest | `KILL`      | Hard-kill the specified execution process group.        |
| `21`   | `0x15` | Host → Guest | `SIGNAL`    | Forwards a POSIX signal (e.g. SIGINT) to process group. |
| `22`   | `0x16` | Host → Guest | `RESIZE`    | Transmits new terminal dimensions (rows, cols) for PTY. |
| `6`    | `0x06` | Host → Guest | `SHUTDOWN`  | Gracefully terminate guest agent and shut down VM.      |
| `16`   | `0x10` | Guest → Host | `STARTED`   | Confirms process spawned with assigned PID.             |
| `17`   | `0x11` | Guest → Host | `STDOUT`    | Standard output data chunk (or combined PTY output).    |
| `18`   | `0x12` | Guest → Host | `STDERR`    | Standard error data chunk (empty for `EXEC_TTY`).       |
| `19`   | `0x13` | Guest → Host | `EXIT`      | Process exit status and termination signal.             |
| `20`   | `0x14` | Guest → Host | `ERROR`     | Execution startup error message.                        |

---

## Message Payloads

### 1. `HELLO` (`0x01`)

```
[0x01] + [Version: UInt32] + [Agent Name Length: UInt16] + [Agent Name: UTF-8]
```

### 2. `EXEC` (`0x02`) and `EXEC_TTY` (`0x07`)

```
[Opcode] + [ID: UInt32] + [TimeoutMS: UInt32]
         + [Argv Count: UInt16] + [Argv Strings...]
         + [Env Count: UInt16] + [Env Strings...]
         + [CWD: String16]
         (+ [Rows: UInt16] + [Cols: UInt16] for EXEC_TTY only)
```

### 3. `STDOUT` (`0x11`) & `STDERR` (`0x12`)

```
[Opcode] + [ID: UInt32] + [Data: Remaining Payload Bytes]
```

### 4. `EXIT` (`0x13`)

```
[0x13] + [ID: UInt32] + [Exit Code: Int32] + [Signal: Int32]
```

### 5. `RESIZE` (`0x16`)

```
[0x16] + [ID: UInt32] + [Rows: UInt16] + [Cols: UInt16]
```

The guest agent handles `RESIZE` by calling `ioctl(ptmx_fd, TIOCSWINSZ, ...)` on the underlying PTY master.

---

## Golden Test Vectors

Shared cross-language serialization vectors are defined in `testdata/protocol-vectors.json`. Both Swift (`Tests/DynoCapCoreTests/ProtocolTests.swift`) and Go (`guest/internal/protocol/protocol_test.go`) execute automated assertions against these shared vectors to ensure binary compatibility.
