Files
glm-5.3-flash f4b5f896b4 docs: sweep em dashes from all markdown prose
Renames the written-usage rule into practice across the contract surface:
docs/ (architecture, research, plans, sdd), tasks/ (all 43 task files,
taskgraph validate passes), AGENTS.md, README.md, CHANGELOG.md, and the
.opencode/agents/ prompts. Every replacement is a sense-preserving
rewrite (colons, semicolons, commas, parentheses, sentence splits, varied),
never a mechanical swap; no spaced hyphens were substituted. Enum fields,
frontmatter, tables, wire data, and cited identifiers survive verbatim;
en dashes inside numeric ranges keep their meaning.

Verification: taskgraph validate (43 tasks), repo grep clean (single
exempt hit: the verification command's own search pattern in AGENTS.md),
cargo test, clippy --all-targets -D warnings, fmt --check, doc all green.
2026-11-04 20:28:00 +00:00

5.3 KiB
Raw Permalink Blame History

status, last_updated
status last_updated
reviewed 2026-10-28

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 have no consumer in scope, OQ-01 resolved)
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, a stated 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 resolved; the feature exists as a tested 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)