The 1.85 claim is now false at the dependency level: the lockfile pins alkcall 0.7.x, and alkcall 0.7.1 raised its MSRV floor to 1.88, so no 1.85 toolchain can resolve this dependency graph regardless of what Cargo.toml declares. Raising the floor keeps the claim honest and aligns with the ecosystem floor. Verified: on a 1.85 toolchain with --ignore-rust-version, the build fails in the graph (icu_locale_core 2.3.0, MSRV 1.86, via alkcall's jsonschema -> idna chain) before any alktunnels code is reached — the raise is dependency-driven, and unlike alktty, two clippy lints promoted since 1.85 surfaced here, both test-only and behavior-identical: - tests/harness.rs: unreachable_code — the hanging-establisher probe ends in a typed Err(EstablishmentError::HandlerError) instead of an unreachable!() cast (the sleep never completes; the per-op timeout cancels the task, so behavior is unchanged) - tests/end_to_end.rs: uninlined_format_args — channel_id inlined into the format! string Version-line bump deferred (crate is unpublished); no CHANGELOG here yet. Verification: - 1.88: test 71 default / 91 all-features pass, clippy --all-targets --all-features -D warnings, wasm32-unknown-unknown check + clippy clean (target component installed) - stable 1.94: test 71/91 pass, clippy --all-targets --all-features -D warnings, fmt, doc --no-deps, wasm32 check + clippy clean
alktunnels
Arbitrary bidirectional tunnels over alkcall
channels: TCP, UDP, unix sockets, and other stream or datagram
substrates — in the ssh -L / ssh -D / ssh -R sense, without SSH.
A producer/consumer protocol crate riding alkcall channels the same
way alktty does (alk/tty is the
sibling precedent): the producer half registers the alk/tunnel open
op and pumps bytes between the channel and the substrate; the consumer
half is the typed session (TunnelSession) that opens tunnel channels
and owns teardown.
A tunnel is a resource, not an address
Open-op params identify a produced resource + substrate:
{ "resource": "postgres-primary", "substrate": "tcp" }
The producer owns the backing — the consumer never learns an address.
Rich addressing (SOCKS5 ATYP, per-datagram remotes) enters only
through the -D/dynamic composition path, inside the tunnel payload,
never in the wire (ADR-001).
- Wire format:
docs/architecture/wire.md(+ the BAST document atdocs/architecture/bast.md) - Open-op params: ADR-001; codec: ADR-003; ALPN: ADR-002
- Producer shapes: ADR-004; consumer session: ADR-005; ACL: ADR-006
- The full spec set:
docs/architecture/(overview, wire, producer, consumer, six ADRs, OQ tracker)
Status
v0.1.0 — the v1 protocol implementation, Phase-2 complete (spec:
docs/architecture/; reviews: docs/reviews/). The wire surface
(params, ALPN, codec) is one-way-door stable from this point; the
API surface becomes ABI-stable at the first external consumer.
Features
| Feature | Contents | wasm |
|---|---|---|
| (default) | params, wire codec, open-op spec, establisher shapes, TunnelSession — protocol only |
yes |
local |
TCP/UDP/unix dial + listen helpers (real sockets) | no |
Verification
cargo test # default crate (wasm-clean)
cargo test --features local # + real-socket suites
cargo clippy --all-targets -- -D warnings
cargo fmt --check
cargo check --target wasm32-unknown-unknown # the wasm-clean guard
License
MIT OR Apache-2.0