Files
alktunnels/docs/architecture
glm-5.3-flash 3a447273a8 docs: resolve OQ-TN-14 — unix in via local, stdio out (alktty owns process stdio)
Split the last open substrate-placement question:

- Unix: ships with the local feature v1 (dial_unix — same halves
  shape as TCP; the wire enum already carried unix per ADR-001;
  the params task's schema list includes all three values)
- Stdio: OUT of scope — a spawned process's stdin/stdout/stderr IS
  alktty's pipe mode (LocalTtyBackend + tokio::process + Stdio::piped,
  alktty tty-local.md): three multiplexed logical streams + the
  exit-code control chunk (alktty ADR-004) + signal forwarding
  (REQ-TTY-02). A stdio bridge here would be alktty's runner mode
  with the terminal stripped out — a strictly worse duplicate that
  also drops the semantics that matter (a byte tunnel has neither
  exit codes nor signals). Remote command execution composes via
  alktty on the same channels substrate.

Updated: open-questions.md OQ-TN-14 (resolved), overview.md feature
gate + deps + OQ summary, producer.md OQ ref, OQ-TN-10 promotion
(#3 split), phase-0-findings + both POC summaries' resolution notes,
params task (schema enum includes unix), local-socket-halves task
(unix ships, stdio does NOT — with the composition rationale),
oq-tn-14-tracker task repurposed (boundary-maintenance: re-opens only
if a consumer needs stdio-without-process-semantics — which would
need its own ADR, or if the alktty/alktunnels boundary needs
sharpening).

Verified: taskgraph valid (12 tasks, no cycles)
2026-09-07 19:44:03 +00:00
..

status, last_updated
status last_updated
draft 2026-09-07

alktunnels — Architecture

Arbitrary bidirectional tunnels over alkcall channels: the alk/tunnel-family producer/consumer protocol crate. This directory holds the architecture spec docs and the ADRs. It is the sibling of alktty's architecture (/workspace/@alkdev/alktty/docs/architecture/) — same substrate (alkcall channels), same shape (a producer open-handler + a typed consumer session), different service (tunnels: raw byte/datagram transport, not terminal sessions).

Documents

Document Status Description
overview.md draft Crate purpose, the resource model in brief, dependencies, ALPN, feature gates, module map
wire.md draft The wire format: open-op params JSON (ADR-001), the data-plane codec (raw pass-through for stream substrates; mandatory [len: u16 BE] framing for UDP — ADR-003), sentinels, half-close semantics
producer.md draft The producer half: the channels/tunnel/sub open op, the establisher (dial + listen variants), the pump handler, registration, scope gating
consumer.md draft The consumer half: TunnelSession (stream + datagram variants), the reverse-flow initiator, teardown ownership (ADR-005)
bast.md draft The BAST (Binary Abstract Syntax Tree) document for the data-plane's binary framing (the UDP [len: u16 BE] codec — ADR-003); the stream pass-through has no binary framing to describe
open-questions.md draft Centralized OQ tracker (OQ-TN-01..14; the Phase 0 ledger promoted)

Applicable ADRs

alktunnels-native ADRs (001..005). Upstream ADRs (alkcall/alknet) are referenced by their own numbers and are NOT ported — the alkcall originals at /workspace/@alkdev/alkcall/docs/architecture/decisions/ remain authoritative for the shared surfaces (establishment, channels wire format, pump_bidi, identity seam).

ADR Title Status
001 Open-Op Params Layout: Resource + Substrate Accepted
002 Single alk/tunnel ALPN (Option A) Accepted
003 Data-Plane Codec: Raw Pass-Through (Stream) / Mandatory Length Framing (UDP) Accepted
004 No TunnelBackend Trait — Halves Functions at the Assembly Layer Accepted
005 The Consumer Session Type Owns Teardown Accepted
006 Access-Control Posture — the Open Gate Is the Security Boundary Accepted

Key Design Principles

  1. A tunnel is a resource, not an address. params identify a produced resource + substrate discriminator; the producer owns the backing (local port, docker container, in-process service, unix socket). No URL-style general addressing in the wire — rich addressing enters only through -D/dynamic composition, which speaks its protocol inside the tunnel payload. See ADR-001 and wire.md.

  2. Role follows the resource; connection direction is independent. Whoever can reach the target is the producer (registers openable channels); whoever wants the bytes is the consumer. -L and -R are the same open op with the entry point on different machines — no protocol-level direction (the hub-owns-the-connection model, OQ-TN-03). Validated by the reverse-flow POC: the worker serves on the connect side; the hub initiates per accept. See producer.md and consumer.md.

  3. Raw pass-through for stream substrates; mandatory length framing for UDP. A tunnel has one data stream per direction — no sub-demux key, no tunnel-level header on stream substrates (0 B tunnel overhead; the channels 8-byte header is the only cost). UDP rides [len: u16 BE] framing — mandatory for correctness (F-2; the rationale and the executable pin live in ADR-003). See ADR-003 and wire.md.

  4. The two-pump shape is alkcall::channels::pump_bidi — never hand-rolled. The producer's pump handler and the consumer-side pump both consume the upstream helper (ADR-050); each pump shuts down the opposite sink on completion (half-close semantics fall out). The OpenHandler's returned JoinHandle tracks the data-plane lifetime (early return = teardown-at-birth, R-02). See producer.md.

  5. No backend trait. Stream substrates need "produce boxed halves for a resource" — a function, not a trait (the UDP POC's OQ-TN-05 finding). The inversion point is the assembly layer wiring substrate halves into the establisher/pump; substrate types stay in feature-gated backend modules. The listen variant (producer accepts instead of dialing) is an establisher shape, not a trait. See ADR-004.

  6. The consumer session type owns teardown. One session = one channel = one tunnel (the channel ID is the flow key). The adopted side has no wrapper awaiting its pump (reverse POC W3) — the session must hold the pump handle and reap the channel on completion/close. See ADR-005 and consumer.md.

  7. Backpressure and limits are inherited, not redefined. Bounded per-channel buffers, the 256-channel cap, monotonic IDs, and the zero-length-sentinel EOF convention are alkcall channels invariants; the tunnel crate consumes them and does not build a second demux/mux (AGENTS.md convention 10).

  8. Security posture: the open gate is the boundary. Scope-gated opens (TUNNEL_OPEN_SCOPE = "tunnel:open", stable once published — ADR-006), alkcall's op-level ACL via register_openable; caller identity resolves in the 0.7.0 precedence order (token > ServingConfig.identity > transport); the establisher/pump handler see the per-call opener identity. No target allowlists, no tunnel-specific policy machinery in v1. See ADR-006 and producer.md.

  9. Wasm-clean default crate. The default crate (protocol only) compiles to wasm32-unknown-unknown; socket/platform I/O lives in feature-gated backend modules (AGENTS.md conventions 4/14), same as alktty.

Relevant Open Questions

All open questions are tracked in open-questions.md. The Phase 0 OQ ledger (OQ-TN-01..10, docs/research/phase-0-findings.md) is promoted there; the questions affecting the spec set are summarized in each doc's Open Questions section.

References

  • Phase 0 research: docs/research/phase-0-findings.md (OQ ledger), docs/research/poc-summary.md (UDP POC), docs/research/reverse-poc-summary.md (reverse-flow POC), docs/research/ssh-socks5-survey.md (SSH/SOCKS5/udpgw prior art)
  • Upstream: alkcall ADR-047 (openable ALPNs are operations), ADR-049 (establishment phase + amendment 2 plan payload), ADR-050 (pump_bidi), ADR-022 §2 (both-sides serving), ADR-047 §5 (connection-owner allocation), ledger CF-005/CF-006 (identity seam); alknet ADR-078 (two-pump contract), ADR-071/093 (channels wire format); alkcall ADR-042 (hub relay)
  • Upstream reviews/ledger (the spec cites these IDs): /workspace/@alkdev/alkcall/docs/reviews/007-establishment-follow-ups-review.md (R-01 = the Establishment plan payload, R-02 = the OpenHandler lifetime contract, R-03 = pump_bidi) and /workspace/@alkdev/alkcall/docs/reviews/consumer-findings-ledger.md (CF-005/CF-006 = the identity seam, resolved in 0.7.0)
  • Sibling precedent: alktty (/workspace/@alkdev/alktty) — the producer/consumer-on-channels shape, wasm-clean default, feature-gated local backend, BAST convention
  • POC code: /workspace/alktunnels-udp-poc (forward), /workspace/alktunnels-reverse-poc (reverse)