Files
alktty/docs/architecture
glm-5.3-flash bc4a9b6024 docs: align remaining alloc-failure references with ADR-010 §2A (prepublish review for v0.3.0)
- README.md ADR index: ADR-010 status notes the §2A amendment
- ADR-009: amendment note records the §2A supersession (in-band path
  shrinks to nothing from registered producers)
- ADR-010 Consequences: dial_failed replaces the stale in-band
  allocate_failed retry-policy bullet
- AllocFailed doc comment + tty-backend.md: describe both failure
  surfaces (direct-path frame / channels-path dial_failed)
2026-09-07 10:04:44 +00:00
..

alktty — Architecture

Terminal session protocol for the alk/tty ALPN: a producer/consumer protocol crate on top of alkcall channels. This directory holds the architecture spec docs, the BAST (Binary Abstract Syntax Tree) document for the wire format, and the ADRs.

Documents

Document Status Description
overview.md draft Crate purpose, the two-carriage model in brief, dependencies, ALPN, backend location map, feature gates
tty-wire.md draft The wire format: negotiation frame (JSON carriage), raw chunk codec ([stream_type: u8][length: u32 be][payload]), control channel split into STREAM_CTRL_IN / STREAM_CTRL_OUT halves, sentinels
tty-bast.md draft The BAST (Binary Abstract Syntax Tree) document for the binary framing layer of the alk/tty wire format (5-byte chunk header + negotiation length prefix); a normative JSON spec conforming to the BAST meta-schema at https://alk.dev/bast/v1/schema. JSON payloads are specified in tty-wire.md and the Rust source, not in the BAST
tty-backend.md draft TtyBackend trait, TtyParams, TtyHandle, TtyControl — the inversion point between the wire-format adapter and the backends. Carries REQ-TTY-01 (backends need not be natively async)
tty-adapter.md draft TtyAdapter (ProtocolHandler on alk/tty): session lifecycle, three-pump bidirectional driver, negotiation errors, exit-chunk ordering (ADR-004), access control, session-cancel cleanup (ADR-005)
tty-local.md draft LocalTtyBackend (the local feature module): portable_pty (PTY) and tokio::process::Command (pipe/runner). Carries REQ-TTY-02 (signal forwarding to the process group)

Applicable ADRs

Ported from the alknet mono-repo and renumbered into alktty's ADR range (001..009; ADR-009 and ADR-010 are alktty-native). The alknet originals at /workspace/@alkdev/alknet/docs/architecture/decisions/ remain the authoritative source for any ADR not yet ported, and for the alknet ADRs referenced by alknet number in the docs below (which are not tty-specific and therefore not ported into alktty's ADR range).

ADR Title Origin Status
001 alktty Wire Format and Two-Carriage Model alknet ADR-052 Accepted (amended 2026-07-18 — Phase 7 control-channel split)
002 TtyBackend Trait and TtyHandle — the Backend Inversion Point alknet ADR-053 Accepted
003 Local TTY Backend Placement (Single Crate with local Feature) alknet ADR-054 Accepted (records both the alknet sibling-crate decision and the alktty single-crate consolidation)
004 Exit Code on a Control Chunk (the Last Chunk Before Stream Close) alknet ADR-055 Accepted
005 Backend Cleanup on Session Cancel (Drop of exit_code Kills) alknet ADR-056 Accepted
006 Self-Contained Negotiation Framing (No alkcall-Internal-Wire-Types Dependency) alknet ADR-057 Accepted
007 TTY Inside Channels — Sub-Streams, Not Wire Format alknet ADR-077 Accepted (reversed by ADR-008 — kept for historical context)
008 Channels Pure Channel Multiplexing (8-Byte Header, No stream_type) alknet ADR-093 Accepted (amends alknet ADR-071/074; reverses ADR-007)
009 The Channels Open Op's input Is the Negotiation alktty-native Accepted (resolves review #001 L1; amended by review #002 R4 — parse failure is a client-visible error frame; amended by ADR-010 — semantic failures move into the establisher)
010 Channels-Path Establishment Failures Move into an Establisher alktty-native Accepted (adopts alkcall 0.5.0 ADR-049; amends ADR-009's R4 amendment; amended 2026-09-07 §2A for alkcall 0.6's plan payload — allocation moves into the establisher, no in-band frame from a registered producer)

Key Design Principles

  1. A terminal session is a terminal concern, not an SSH or Docker concern. SSH and Docker are two backends that can allocate a PTY. alktty owns the terminal session lifecycle; the backends (DockerTtyBackend, SshTtyBackend, LocalTtyBackend) implement a TtyBackend trait. This dissolves the PTY hedge in the alknet-ssh research (DP-5): PTY is not an SSH feature delegated to a separate crate, it's a tty feature that SSH happens to be able to provide. See overview.md and ADR-002.

  2. Two-carriage model: JSON negotiation, then raw chunks. The bidi stream opens with a single length-prefixed JSON negotiation frame (terminal params, backend selector, command), then switches to a raw chunk format ([stream_type: u8][length: u32 be][payload]) for the life of the session. The call protocol's JSON-RPC shape handles the structured request; raw bytes handle the body, which is what a terminal actually is. No per-chunk EventEnvelope overhead, no base64. See tty-wire.md and ADR-001.

  3. Fixed channel set, not extensible. Five stream types (0=stdin, 1=stdout, 2=stderr, 3=ctrl-in, 4=ctrl-out), no negotiation. A 6th channel type is a wire-format change (one-way door); the ALPN model handles extensibility at the protocol level (a new ALPN is cheap, a wire-format change is not). The impoverishment vs SSH channels is the feature: alktty multiplexes one service (a terminal session) with a fixed channel structure, not arbitrary services. See tty-wire.md.

  4. The backend trait is the inversion point. alktty defines TtyBackend; the backend crates implement it. alktty depends on alkcall; backends depend on alktty for the trait; alktty does not depend on any backend. This preserves alknet ADR-003's no-handler-depends-on-another-handler rule. alktty does not depend on alkcall's internal wire types either (the negotiation framing is self-contained — ADR-006). See tty-backend.md and ADR-002.

  5. Backends need not be natively async (REQ-TTY-01). The trait's adapter-facing types (AsyncWrite, Stream<Item = Bytes>, BoxFuture, TtyControl) are the adapter's contract. A backend may expose blocking handles internally and bridge them via std threads + tokio mpsc/oneshot (the pattern portable_pty requires, and the local-PTY POC validated). The bridging pattern is a documented, supported implementation strategy. See tty-backend.md and tty-local.md.

  6. Exit code on a control chunk, last before stream close (ADR-004). {"type":"exit","code":N} rides on STREAM_CTRL_OUT (stream_type 4) and is the last chunk before the server closes the write half. This gives coordinators deterministic completion notification — no polling, no plugin state. The adapter owns the ordering; backends resolve exit_code and the adapter awaits, sends the chunk, closes. See tty-adapter.md.

  7. Drop of exit_code future kills the session target (ADR-005). On session cancel (connection drop, stream reset), the adapter drops the TtyHandle, which drops the exit_code future without driving it to completion. The backend's exit_code future's Drop-on-cancel MUST kill the child/container/SSH process. This is a behavioral contract on the TtyBackend trait — the adapter has no separate kill method; the cleanup is wired into the exit_code future's Drop by the backend. See tty-adapter.md and tty-local.md.

  8. The runner pattern is preserved, not specialized. The local backend in pipe mode (terminal: None) is a process-streaming endpoint — the same shape as GitHub/Gitea Actions runners, just over alk's transport instead of HTTP polling. alktty provides the mechanism (framed byte stream + exit code); runner policy (job management, log persistence, task graph) is a downstream crate's job. See tty-local.md and ADR-003.

  9. TTY always uses its 5-byte format, including inside channels (ADR-008). The same wire.rs code runs in both direct alk/tty and channels alk/channels modes; only the BiStream source differs. The channels layer strips its 8-byte header and hands TTY the payload transparently. This reverses the earlier two-mode design (ADR-007, kept for historical context). See tty-adapter.md.

Relevant Open Questions

OQ Title Status Relevance
OQ-43 TtyControl trait object Clone constraint resolved control: Option<TtyControlHandle> via a #[derive(Clone)] newtype wrapping Arc<dyn TtyControl + Send + Sync>; the trait is NOT Clone (not object-safe) — the newtype carries Clone-ability
OQ-44 Terminal modes (TTY modes) deferred(scope) TerminalParams.modes reserved; default terminal modes suffice for current scope; blocked on a concrete mode-control use case
OQ-45 Flow control for high-throughput stdout resolved QUIC per-stream flow control is the backpressure mechanism (chain complete by construction); no application-level windowing. Reversal is an additive ControlMessage variant, not a wire-format change
OQ-46 Runner API surface deferred(scope) The runner mechanism (pipe mode) is in alktty; runner policy (job management, log persistence, task graph) is a downstream crate, not in scope here
OQ-47 Stdin closure canonical signal resolved Either a zero-length stdin chunk or a {"type":"eof"} control chunk; both are accepted; the spec recommends eof for explicitness

References

  • docs/plans/project-setup.md — the current plan (phases 05). All five phases are landed: Phase 4 landed this directory (architecture docs + BAST schema + renumbered ADRs); Phase 5 landed the tests, including the integration tests in tests/ at the crate root.
  • alknet originals of the ported ADRs (alknet ADR-052, 053, 054, 055, 056, 057, 077, 093) at /workspace/@alkdev/alknet/docs/architecture/decisions/ — the authoritative source for any ADR not yet ported, and for the alknet ADRs referenced by alknet number in the docs above (which are not tty-specific and therefore not ported into alktty's ADR range).
  • alktype BAST format spec — the normative format spec for BAST documents (the meta-schema tty-bast.md conforms to); see also /workspace/@alkdev/alktype/docs/architecture/bast-format.md.
  • alkcall architecture README at /workspace/@alkdev/alkcall/docs/architecture/README.md — the producer/consumer protocol-crate pattern alktty follows.