> ## Documentation Index
> Fetch the complete documentation index at: https://www.agentworldprotocol.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Frame format

> The 28-byte binary header, the optional extension block, and the inline JSON form.

See the normative layout in [spec/transport/frames](/spec/transport/frames). Quick reference:

```
0        4   5   6      8            16           24        28
+--------+---+---+------+------------+------------+---------+
| "AWPF" |ver|flg|chan  | seq (u64)  | ts_mono_ns | len(u32)|
+--------+---+---+------+------------+------------+---------+
                                                             \
  if flg bit 2:  28        30                                 30+ext_len
                 +---------+---------------------------------+----------
                 | ext_len | TLV entries: type u8, len u8, v… | payload…
                 +---------+---------------------------------+----------
  else:          28
                 +----------
                 | payload…
```

Little-endian throughout. Flags: bit 0 keyframe, bit 1 end-of-burst, bit 2 has\_extensions, bit 3 resync (first frame after a discontinuity; always a keyframe), bits 4–7 reserved (zero on send, ignored on receive). Extension types: `0x01` tick (u64), `0x02` ts\_sim\_ns (i64), `0x03` ts\_send\_ns (u64), `0x80`–`0xFF` vendor. `payload_len` counts payload bytes only.

## Inline JSON form

In the `inline` binding the same frame is an `obs.frame` or `cmd.frame` notification (AWP-DAT-004):

```json awp:obs-frame theme={null}
{ "jsonrpc": "2.0", "method": "obs.frame",
  "params": { "channel_id": 1, "seq": 42, "ts_mono_ns": 913005200000, "flags": 1,
              "tick": 4212, "ts_sim_ns": 4212000000,
              "payload_b64": "eyJhdmF0YXIiOlsyLDNdfQ==" } }
```

`flags` in JSON carries bits 0, 1, and 3 only; extension values are the named fields `tick`, `ts_sim_ns`, and `ts_send_ns` (vendor extensions: `x-<vendor>.<name>`). A streaming observation frame carries its send time (test vector `streaming_ts_send`):

```json awp:obs-frame theme={null}
{ "jsonrpc": "2.0", "method": "obs.frame",
  "params": { "channel_id": 1, "seq": 4211, "ts_mono_ns": 913004112000, "ts_send_ns": 913004120200, "flags": 1,
              "payload_b64": "eyJhdmF0YXIiOlsyLDNdfQ==" } }
```

## Worked example

Keyframe on channel 1, seq 42, `ts_mono_ns` 913005200000, tick 4212, 16-byte payload (test vector `keyframe_tick`):

```
41 57 50 46  01  05  01 00                          magic, version 1, flags 0b101, channel 1
2a 00 00 00 00 00 00 00                             seq = 42
80 c2 59 93 d4 00 00 00                             ts_mono_ns = 913005200000
10 00 00 00                                         payload_len = 16
0a 00                                               ext_len = 10
01 08  74 10 00 00 00 00 00 00                      tick (0x01, len 8) = 4212
7b 22 61 76 61 74 61 72 22 3a 5b 32 2c 33 5d 7d     payload  {"avatar":[2,3]}
```

All vectors, including the malformed ones a decoder must reject, are in [`schemas/test-vectors/frames.json`](https://github.com/Hyperduality/agent-world-protocol/blob/main/schemas/test-vectors/frames.json) and are exercised by the reference decoder in CI (AWP-DAT-008).
