Traversio

Architecture

How Traversio is layered, which boundaries are stable, and where the implementation still needs refinement.

What This Page Is For

This page is about how Traversio is built.

If you are trying to use the public API, start with Mental Model first. That page already covers:

  • the public object graph
  • the difference between connection, channel, session, and SFTP client
  • which top-level API to reach for first

This page starts one layer lower:

  • how the package is split conceptually
  • where protocol state lives
  • which implementation constraints are deliberate
  • which seams still need hardening

Layer Diagram

Your code
    |
    v
Public API wrappers
    SSHClient / SSHConnection / SSHSession / SFTPClient / forwarding wrappers
    |
    v
Connection and forwarding orchestration
    |
    v
SSHTransportProtocolClient actor
    - version exchange
    - key exchange
    - encrypted transport
    - authentication sequencing
    - channel lifecycle and flow control
    |
    +--> Authentication helpers
    +--> Connection message coders
    +--> SFTP protocol helpers
    |
    v
Wire and algorithm layers
    - SSH binary framing
    - typed message codecs
    - key derivation
    - cipher/MAC handling
    |
    v
Transport abstraction
    SSHByteStreamTransport
    |
    v
Apple 26+ Network.framework backend

These are logical layers first. The public library still ships mainly as one Swift target while those boundaries settle, with small helper targets where platform or validation work requires them.

Working Source Layout

The source tree currently reflects those boundaries under Sources/Traversio/:

  • Transport/
  • Wire/
  • Algorithms/
  • Authentication/
  • Connection/
  • Forwarding/
  • SFTP/
  • TransportProtocol/
  • Client/

Main Constraints

  • Apple platforms first
  • first public transport path targets platform release 26 and later
  • Swift Concurrency is the default model
  • the SSH core must stay testable without a live network
  • transport details stay isolated
  • the first meaningful milestone still needs exec, shell, SFTP, and forwarding

Transport Layer

Purpose

SSH is defined over a reliable byte stream. Traversio therefore keeps a byte-stream abstraction so the protocol layers stay portable while the first concrete backend is Apple-specific.

Direction

The first transport backend uses the new Network framework API family available on Apple platform release 26 and later. The transport layer provides:

  • async send
  • async receive
  • orderly connection lifetime around a single byte stream

This keeps the SSH core separate from Apple transport types while still using the preferred modern APIs first.

Wire Layer

The wire layer owns deterministic byte-level SSH behavior:

  • primitive encoding and decoding
  • packet framing
  • identification parsing
  • binary readers and writers
  • typed transport and connection messages

Design rules:

  • the wire layer should be testable without a live connection
  • the wire layer stays focused on byte-level SSH behavior

Algorithms Layer

Implemented interoperability path:

  • curve25519-sha256, [email protected], and ecdh-sha2-nistp256 key exchange
  • Ed25519, RSA SHA-2, and ECDSA host-key verification
  • password auth
  • keyboard-interactive auth
  • Ed25519, RSA/SHA-2, and ECDSA public-key auth
  • aes128-ctr / aes256-ctr packet protection with HMAC-SHA-2 and OpenSSH UMAC MACs, including classic and ETM forms
  • OpenSSH [email protected] / [email protected]
  • OpenSSH [email protected]
  • OpenSSH [email protected] strict-kex marker handling on the initial exchange

The project prefers Apple system frameworks where practical, and algorithm coverage remains intentionally focused while the protocol core hardens.

Transport Protocol Engine

This layer owns the SSH transport state machine:

  • version exchange
  • SSH_MSG_KEXINIT
  • key exchange
  • transition into encrypted packet flow
  • service requests
  • inbound and outbound sequencing
  • selected post-auth transport messages such as SSH_MSG_EXT_INFO and SSH_MSG_DEBUG

Mutable protocol state is actor-owned so sequencing stays explicit.

Authentication Layer

Public auth methods:

  • password
  • keyboard-interactive callbacks
  • Ed25519 and ECDSA public key from raw private-key bytes
  • RSA public key from PKCS#1 DER private-key bytes
  • Ed25519, RSA, and ECDSA public key from OpenSSH private keys, including the current bcrypt + AES encrypted-key path
  • OpenSSH key-pair generation for Ed25519, ECDSA P-256/P-384/P-521, and RSA, including matching authorized-key output

Trust posture:

  • the caller must choose a host-key policy
  • exact pinning plus known_hosts import for exact, wildcard, negated, hashed, CIDR, @revoked, and @cert-authority entries are available
  • trust-on-first-use, changed-key helper, and async trust callbacks are public
  • trust-any is explicit and not implicit fallback

Follow-up work:

  • broader host-key trust behavior
  • broader credential-loading options such as agent-backed auth

Connection And Channels

Above the transport actor, the connection layer is responsible for:

  • connect lifecycle orchestration
  • authentication sequencing
  • channel allocation
  • session-channel exec and shell flows
  • transcript collection
  • channel window tracking for send and receive paths

The public connection wrapper exists in two forms:

  • explicit long-lived ownership through SSHClient.connect(configuration:)
  • closure-scoped convenience through SSHClient.withConnection(configuration:_:)

The planned direction for the first stable release is:

  • one SSH connection must support multiple concurrent shell, exec, SFTP, and forwarding channels
  • reconnect remains an upper-layer concern
  • shell, streamed exec sessions, and raw forwarding channels already expose event-based stream surfaces, and richer shell control plus final forwarding lifecycle semantics remain release work

SFTP

The current SFTP design is actor-based and routes replies by SFTP request ID inside one subsystem session:

  • requests go through one actor-owned channel/session pair
  • replies are matched back to the correct waiter by request ID
  • path operations and handle operations on one SFTPClient can overlap safely
  • high-level bulk helpers keep a simple whole-file model

That keeps protocol coordination localized without forcing callers to open a second SFTP subsystem just to overlap simple metadata or handle work.

The release-scope question has shifted. Traversio already supports overlapping in-session requests, and fuller bulk-transfer engines remain future work.

The first concrete trigger for another round of SFTP work should be a real requirement such as:

  • read-ahead
  • pipelined writes with bounded in-flight windows
  • throughput isolation between independent long-running transfers

Forwarding

Forwarding is part of the implemented surface. Traversio includes a raw direct-tcpip public wrapper, Apple 26+ local-forwarding and dynamic-SOCKS helpers built on NetworkListener, a raw remote-forward listener, and a remote-forwarding helper that bridges remote listeners back to one local TCP endpoint. The main remaining work is:

  • stronger lifecycle contracts for the local, dynamic, and remote forwarding helpers
  • broader interoperability evidence outside the current OpenSSH-heavy and local proxy-matrix baseline
  • clarity on whether the tightened actor-plus-pending-queue coordination should remain the release design or later become a dedicated mailbox/dispatcher

The release scope keeps two points explicit:

  • local, remote, and dynamic forwarding are all required and already exist as public APIs
  • forwarding failures should default to the forwarding scope unless the caller chooses a stronger policy

Main Structural Risk Today

The largest structural risk is the size and responsibility load of SSHTransportProtocolClient.

That actor carries too much of:

  • post-auth sequencing
  • channel routing
  • forwarding coordination
  • SFTP/session plumbing

It remains workable, and future protocol work should keep reducing that concentration of responsibilities.

On this page