--- status: draft last_updated: 2026-09-07 --- # alktunnels — BAST Document for the `alk/tunnel` Wire Format This document is the **BAST (Binary Abstract Syntax Tree)** specification for the binary portions of the `alk/tunnel` wire format — per AGENTS.md convention 12, the mandatory UDP length-framing codec ([ADR-003](decisions/003-codec-and-udp-framing.md)) is binary framing beyond pass-through, so the BAST document exists even though the format is trivial. It is a normative JSON document conforming to the BAST meta-schema at `https://alk.dev/bast/v1/schema` (JSON Schema Draft 2020-12); any Draft 2020-12 validator can check well-formedness. **alktunnels does not depend on alktype.** The hand-rolled `frame_datagram` / `DatagramReader` (the `src/wire.rs` shape the POCs ran) is the runtime codec; this BAST document is the human-readable contract describing what those functions round-trip. If runtime validation against the BAST becomes desirable later, alktype becomes an optional dep and this document is there to feed it. ## Scope The `alk/tunnel` wire format is: a JSON open op on the channels call plane (a UTF-8 JSON object inside the channels envelope — not a binary layout; specified in [wire.md](wire.md) §The Open Op and implemented by `TunnelParams`/`tunnel_open_spec` in the Rust source), and a binary data plane inside the channel `BiStream`. Per the BAST format spec, a BAST document describes **binary data layouts** — not JSON payloads ([`validate_bytes` vs `validate_json`](https://alk.dev/bast/v1/spec)). This document therefore covers only the data plane's binary framing: 1. **The datagram frame** (`[len: u16 BE][datagram bytes]`) — the UDP-substrate codec (ADR-003; mandatory, F-2). Stream substrates ride raw pass-through — zero tunnel-level framing, so there is nothing for BAST to describe there. What this BAST deliberately does **not** cover: - **The open-op params JSON shape** (`{resource, substrate}`) — UTF-8 JSON on the call plane; specified in [ADR-001](decisions/001-open-params-layout.md) and [wire.md](wire.md), implemented by `TunnelParams`. - **The channels 8-byte chunk header** — the channels layer's own framing (alknet ADR-071/093); stripped transparently before the tunnel data plane sees bytes. Specified upstream, not here. - **The EOF sentinel** — the channels-level zero-length chunk (upstream); the tunnel codec never emits it (that is the F-2 invariant). ## The BAST document ```json { "$schema": "https://alk.dev/bast/v1/schema", "$defs": { "DatagramFrame": { "kind": "struct", "endian": "big", "fields": [ { "name": "len", "kind": "uint16" }, { "name": "datagram", "kind": "bytes", "encoding": "length-prefixed", "maxLength": 65535 } ] } } } ``` ## Annotations ### `DatagramFrame` — binary, exact Maps 1:1 to the on-wire bytes. `len` as `uint16` big-endian (2 bytes) followed by exactly `len` bytes of datagram payload. The zero-byte payload (`len == 0`) is a legal empty datagram — a real datagram, NOT EOF (the F-2 invariant; EOF is the channels-level sentinel, outside this codec). The `maxLength: 65535` encodes the u16 bound; the codec rejects framing a larger datagram at frame time (`Oversize`) rather than wrapping the length field. One frame per datagram, in both directions of the channel `BiStream`. Frames are self-delimiting on the byte stream; a decoder is an incremental state machine across chunk boundaries (chunk splitting/batching is transparent — forward POC, 7-byte chunk splits verified). ### Layering note The codec sits at the substrate/pump boundary (the establisher wraps the dialed UDP half in the framed adapter — ADR-003's placement, so the pump handler stays substrate-agnostic). The BAST describes the wire inside the `BiStream` only; the pump/pump_bidi contract (ADR-050) is upstream's, not re-specified here. ## References - [ADR-003](decisions/003-codec-and-udp-framing.md) (the codec decision + F-2 mandate), [ADR-001](decisions/001-open-params-layout.md) (the JSON open-op shape — outside BAST scope) - [wire.md](wire.md) (the normative prose; §Normative byte diagrams) - alktty `tty-bast.md` (the BAST precedent — same meta-schema, same "binary framing only" scope rule) - Forward POC `docs/research/poc-summary.md` §3 (the codec's validation matrix); reverse POC `docs/research/reverse-poc-summary.md` §F-2 (the mandate)