Files
alkssh/docs/architecture/overview.md
T
glm-5.3-flash 1bfd07adfc docs(architecture): the four spec docs — overview, mapping, client, auth
- overview.md: two-doors framing, family-position table, surface
  categories, bounded-resources policy (max_auth_attempts 10,
  keepalives 15s/3, per-channel caps), non-goals, lifecycle note
- mapping.md: the spine — channel/request rows (git exec-only, route-1
  bridge, translation-bridge session rows), parse-only dispatch,
  global-request rows, spawn-and-return constraint, per-build decline
  matrix
- client.md: dial surface (key source + host-key policy + keepalives),
  op rows (family types in, vanilla out), fail-closed acceptor
  (not russh's accept-and-drop), lifecycle primitives only, POC
  correctness facts carried
- auth.md: the fingerprint bridge + dispositions summary (server),
  vault custody + two-case host-key policy (client)
- README index: doc table filled, current state updated
2026-10-27 03:07:17 +00:00

5.3 KiB
Raw Blame History

status, last_updated
status last_updated
draft 2026-10-27

Overview — alkssh

What this crate is

alkssh is the alk family's SSH adapter (family ADR-003): a thin wrapper around russh that terminates the vanilla-SSH wire and bridges to/from family protocols. It is a door in both directions, vanilla on the outside (vision principle 2; ADR framing in mapping.md / client.md):

  • Server direction — a door for vanilla clients: vanilla ssh, git, and (never for us, by design) sftp tooling connect as they would to any sshd; each accepted SSH channel/request is mapped onto exactly one family protocol seam and exactly one cargo feature. Primary current purpose: the alkforge git door.
  • Client direction — a door to vanilla servers: a family app (the reverse-runner hub) dials vanilla sshd (rented fleets, runpod/vast.ai-style boxes) and the ops map family-side onto alktty/alktunnels/alkgit types; the runner stays vanilla by design.

The crate's substance is glue and mapping; no SSH framing is authored in-family (family ADR-003 decision 1) — russh owns the wire, and the pin is ADR-002.

Position in the family

Concern Owner
SSH wire protocol (KEX, ciphers, channel mux, userauth state machines) russh (pinned, ADR-002)
SSH channel-type → family-protocol mapping this crate (the spine, mapping.md / client.md)
Identity (fingerprint → Identity) alkcall IdentityProvider, assembly-implemented; never the vault (vault = secrets we hold)
Secrets we hold (client dial keys, host keys) alkvault-backed sources (ADR-005)
The alk/ssh ALPN ADR-001 (edge-termination contract; relay/browser legs deferred, OQ-01)
Deployment policy (which features, which ACLs) the embedding assembly (alkforge)

Composability boundary: alkssh is a door, not a backend — it depends on alkcall types at the wire layer and the mapped crates' session or client surfaces, and carries no deployment policy. A downstream app embeds it, enables features (ADR-003), brings identity/ACL config.

Public surface (categories)

The crate is a library ([lib], no binary — non-goal); the surface categories the phase-1 specs define:

  • Server stack (mapping.md): serve configuration (feature-gated seam wiring, bounded-resource limits, honest-advertisement auth config) + the serving loop that accepts vanilla connections and dispatches per the mapping table.
  • Client stack (client.md): dial surface (address, key source, host-key policy, keepalive/timeout config), the op-row consumers (session exec/pty, tunnel dial, -R listen + acceptor), and lifecycle primitives (bound-port handles, cancel — OQ-12: no reconnect policy is owned).
  • Key sources (auth.md): vault-backed source construction per ADR-005 for both directions (client keys and host keys).
  • Identity plumbing (auth.md): the fingerprint→identity bridge at the server; the identity→seam propagation for mapped channels.

Feature graph (ADR-003): session, git, tunnel, sftp (placeholder) — flat, independent, default = [] (no capabilities), two-direction symmetry, fail-closed declines contract-tested on every side of every feature.

Bounded-resources policy (family convention)

Every session is bounded by wall clock, size, and channel count (AGENTS.md convention 9; the knobs are russh's Config per ADR-002's surface notes):

Resource Knob Default posture
Session wall clock inactivity_timeout set (assembly-tunable)
Rekey volume/time Limits russh-enforced (post-0.64-full-enforcement)
Per-channel memory window_size, maximum_packet_size, channel_buffer_size set
Auth attempts max_auth_attempts 10 default (ADR-004: the counting none probe)
Keepalives (client direction, cloud fleets) keepalive_interval/keepalive_max 15 s / 3 (reverse-runner evidence: NAT'd runners)
Concurrent channels per session ours (in-crate) + per-identity policy when bridged ours to cap

No unbounded loops, no unbounded buffers — the fail-closed declines plus the knobs above are the whole posture.

Non-goals

Per vision.md: no in-family SSH protocol machinery (ever); not an sshd (no local accounts, no OpenSSH authorized_keys semantics, no PAM); no sftp serving until alkfs lands (OQ-13 — the feature exists as a declining placeholder); no binary/CLI; no password or keyboard-interactive auth in either direction; no x11 or agent forwarding at all (not even feature-gated — ADR-003 §5).

Lifecycle note

This crate follows the family crate template (alktty root pattern): src/ modules re-exported from lib.rs, one module per file, public API = crate-root re-exports. The dependency set (russh per ADR-002, alkcall types, per-feature sibling deps: alktty/alktunnels/alkgit) and the manifest (rust-version 1.89, edition 2024) land at implementation start — ADR-002 records the manifest decisions.

References

  • README.md (index), open-questions.md (OQ-01…13)
  • ADRs 001–006 in decisions/
  • docs/research/ — vision, POC findings (1/2/3), russh inventory, auth bridge, mapping table (validated), reverse-runner extraction
  • Family ADR-003 (the structural decision), family ADR-002 (alkforge; why exclusion matters)