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.
5.3 KiB
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,-Rlisten + 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)