Skip to content

podssh v1.0.0-beta.1

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 30 Oct 12:26

podssh v1.0.0-beta.1

The first beta since this repository's history was replaced: it carries
each change since 2026-10-08. A beta is a prerelease. Its tag never moves:
a defect found in it goes into the next beta.

The files

File For
podssh-x86_64-unknown-linux-musl Linux on x86-64, static: no library and no loader needed
podssh-aarch64-unknown-linux-musl Linux on aarch64, static
podssh-x86_64-pc-windows-msvc.exe Windows on x86-64, with a static C runtime
SHA256SUMS The SHA-256 of each binary
THIRD-PARTY-LICENSES.md The licenses of the crates in the binaries, with their texts

Check a download

T=v1.0.0-beta.1; B=podssh-x86_64-unknown-linux-musl   # or podssh-aarch64-unknown-linux-musl
curl -fsSLO "https://github.com/Azathothas/podssh/releases/download/$T/$B"
curl -fsSLO "https://github.com/Azathothas/podssh/releases/download/$T/SHA256SUMS"
grep " $B\$" SHA256SUMS | sha256sum -c - && chmod +x "$B"
./"$B" --version   # podssh 1.0.0-beta.1
./"$B" doctor      # what this host allows, and whether the whole path works

On Windows, compare (Get-FileHash podssh-x86_64-pc-windows-msvc.exe).Hash
with its line in SHA256SUMS (the case of the letters differs).

What works

podssh ssh, each, containers, proxy, pipe, cp, mv, scp,
sftp and edit, doctor, keygen, agent, man, status, ping,
health, node, operator, relay, chat, play and config, and
mcp. podssh man is the reference: each command, flag, -o keyword,
variable, file and exit code. These binaries have no Tailscale and no iroh
road: podssh ts, and a destination iroh:TICKET or --iroh-ticket, exit
with 70 and say so.

What to test again

What the earlier betas asked for, and this beta has:

  • ssh_config, -F, -G and Match (#14, #22).
  • A relay session that drops: the hop that broke is named, and a forward is
    tried again when that is safe (#17).
  • Copies (#21): podssh cp continues after a drop, writes a temporary
    name, checks the digest and then renames; pipelined SFTP, parallel chunks,
    delta copies, -r, --delete, --dry-run, progress and a bandwidth
    limit; scp and sftp with OpenSSH's command lines; edit; ZMODEM.
  • Output for machines: doctor --json, man --json, status, ping,
    health, and the exit status of a remote command (#23).
  • Many hosts: each, broadcast with an emergency stop, recordings and
    play (#24).
  • Streams that are not SSH: pipe, -W, AF_UNIX streams, UDP over the
    relay (#26).
  • podssh doctor in your sandbox, with and without HTTPS_PROXY; a
    no_proxy with blocks such as 10.0.0.0/8 keeps each address inside
    them off the proxy now, and doctor names the entry (T-316).

What a beta does not have yet

  • Build provenance and signed checksums (T-210, T-211): SHA256SUMS comes
    from the run that built the binaries, and is not signed.
  • macOS, Linux armv7 and riscv64, and Windows aarch64 binaries (T-218).
  • The check of a release from end to end with no human (T-251); it runs
    before v1.0.0.
  • Known, for the next beta: a proxy that answers 200 to CONNECT and then
    carries no SSH is not named as the cause (T-317).

Report a defect

Open an issue at https://github.com/Azathothas/podssh/issues with the
output of podssh --version and podssh doctor --json. Read that output
before you post it: it names this host's proxy and addresses, and never a
token or a password.

The licenses of the crates in the binaries, with their texts: THIRD-PARTY-LICENSES.md.

The commits of this release

Commands

  • podssh ssh: the native client, on russh (e34597b)
  • podssh doctor: what a host allows and whether the relay path works (7b38e31)
  • podssh keygen: SSH keys in OpenSSH's format, for hosts without ssh-keygen (9b806fe)
  • podssh man: the whole manual from the binary, as text (d0b16a3)
  • podssh ssh: each flag of OpenSSH 10.3p1 answers by name (0c93a7c)
  • podssh ssh: a repeated flag follows OpenSSH; -J and -W only once (3ee70dc)
  • podssh status: one line of JSON about this host (692b3b0)
  • podssh agent: an SSH agent inside podssh, on a socket that only this user can open, with add, list, remove, lock and unlock (T-034) (f7d5640)

Build and CI

  • Workflows: artifact actions on Node 24; dumpbin found with vswhere (3937707)
  • scripts/sandbox-check.sh: the sandbox measurement as one command (4853e6c)
  • scripts/test_in_box.sh: a Podman box built to the target sandbox's profile (4f66d9b)
  • gate: the no-C rule also stops C++ (CXX=/nonexistent) (a378863)
  • CI runs the console checks on Windows, against MSYS2's sshd (dacbf4a)
  • CI runs each step of the gate in a job of its own, at the same time (a04b0c8)
  • scripts/dev.sh in two files, each under 500 lines, and the size check reads the scripts (d88de09)
  • CI pulls each pinned image through a fallback: when Docker Hub refuses a pull with no account, a mirror serves the same digest (5557c62)
  • CI names the systems of its runners, ubuntu-24.04 and windows-2025, before ubuntu-latest moves to Ubuntu 26 on 2026-10-19 (T-278, partial) (0804e38)
  • scripts/gate.sh tries each download of rustup and apk three times, 10 s and then 20 s apart, as CI at 0d3d13a failed in its step msrv_ts when one DNS lookup of rustup's channel file failed on the runn… (73f910b)
  • scripts/fuzz.sh builds and runs each fuzz target for this host's own target, as the first run of the workflow fuzz found that a release binary of cargo-fuzz, built for musl, built the targets for musl… (6529789)

Documents

  • docs: design.md, the answers that decide podssh's future (bcbccf1)
  • Docs, pass 1: the routing documents in ASD-STE100, and docs/defects.md (3c7734a)
  • Docs, pass 2: STATUS and ROADMAP in ASD-STE100 (5b9805f)
  • Docs, pass 3: the topic pages in ASD-STE100, brought up to date (6649623)
  • Docs, pass 4: design, milestone pages and release notes in ASD-STE100 (3a88e1d)

Repairs

  • Fix -4/-6, the 1001 exit, -W on a lost connection, two messages (72dc8a6)

Other

  • podssh: initial public release (9a03102)
  • STATUS: the gate re-run is green, interop 62 of 62 (32a2837)
  • podssh-ws: never proxy loopback; drop three unused dependencies (f9dda61)
  • Roadmap: the operator's decisions on the way to a finished podssh (fd259f8)
  • podssh-relay: relay hosts with failover, in a C-free library crate (b45fcb4)
  • Liveness: ping the relay, declare a silent link dead in 30 s (a00c7a2)
  • No proxy and no DNS: pinned addresses, DNS over HTTPS, RSA in TLS (a89deaf)
  • Fault injection in the gate; the dead DNS stack in podssh-transport removed (c078085)
  • Interactive use on Windows, measured in a real pseudo console (ca50a68)
  • Release notes for v0.1.0-beta.1: doctor, keygen, failover, the fault harness (aa9cfaa)
  • Prompts: no wait for ever on a terminal that nobody watches (eacd94e)
  • TODO/: the work record, with its checker in Rust and in the gate (22c3b88)
  • TODO/: T-249, a cited line that moved still exists (e275d36)
  • AGENTS.md: a session runs unattended toward v1.0.0 (b1b111b)
  • One release only: v1.0.0, tagged once at the end (4bf0c26)
  • The box has the sandbox's dead /dev/tty; T-005 measured there (d272ebb)
  • podssh-todo: remap moves the citations of an edited file; a quote must hold (cd12fa3)
  • sandbox-check.sh: each step has a verdict, and a failed step fails the run (eaf9822)
  • IPv6 addresses as targets: podssh sends the bare literal to the relay (2da855f)
  • Relay tokens: one cache entry for each deployment, with the host that minted it (37ace00)
  • A command that is not implemented says so before the --timeout gate (3cd368b)
  • A flag with no value names the flag and its value (56b466b)
  • podssh --help and --version drop no word (4bceef6)
  • A host that starts with -: refused also as HostName, and -- is documented (475aea9)
  • A refusal names keys only when keys were tried (80f20bf)
  • A dropped session names the hop that broke (25ab0e7)
  • The -R refusal gives its own cause, not the listener (cd3fea5)
  • A bad relay variable is a configuration error (78) (fdbba30)
  • The help of a command that does not work says so (02e4e1f)
  • podssh man relay-facts selects THE RELAY (9fefff2)
  • Each answer of the server while logging in has a time limit (8d668b7)
  • A channel that podssh did not ask for is refused (5c7a1ad)
  • The % tokens are OpenSSH's (5521cbf)
  • -W takes HOST:PORT, as OpenSSH reads it (d87ca8a)
  • podssh doctor gives the version and the age of the compiled-in roots (2c39778)
  • An interactive session over -tt from the box: vi, less, top and Ctrl-C (bc13eee)
  • podssh doctor --json (332ee58)
  • podssh man --json (a2eeb7f)
  • PODSSH_TIMEOUT gives the default of --timeout (bd626c7)
  • podssh doctor --full logs in to GitHub with a key made for the check (d98d77e)
  • T-052 measured in the box: login ok (c6f09a8)
  • The node leg's control leaves as a text frame (3d4785a)
  • A Close from the relay keeps its code and reason (6d7737f)
  • The node leg sends data only for a readied session (1a00ba2)
  • An HTTP answer to an upgrade keeps its body and follows the contract (4b6e917)
  • A host or a pair name cannot change the relay path (3b60753)
  • A control frame that RFC 6455 forbids fails the connection (076e3ce)
  • cargo todo check finds a citation that a forgotten remap left (4e817d7)
  • No crate carries a verifier that accepts each certificate (510d86f)
  • No draw of random bytes can panic (c56792f)
  • A library can bring its own rustls configuration (723d90b)
  • A session's failure has a class (23b5d82)
  • A plain ws:// session to the loopback, for tests (3632dcb)
  • Pairs of the reverse road, made, asked about and stopped (9811e0d)
  • The node of the reverse road (c3a3ca9)
  • The operator of the reverse road (0d92eef)
  • A blocking facade for podbox (af0a163)
  • The node and the pairs on the command line (3cbf215)
  • The operator, and ssh to a node (e8bbd4d)
  • The codecs of the reverse road in podssh-relay (cd75137)
  • The reverse road has no idle cut, and drops at random (0052ac9)
  • A live test of the drops of reverse sockets, and a workflow to run it (b082b83)
  • A dropped link of the reverse road is named as one (e1ba5ba)
  • The build and box images, pinned to digests in one place (19ca632)
  • Dependabot for the crates, the actions and the pinned images (1f89a82)
  • A stalled local side ends its own session, not the node's (a9c9c2f)
  • The list of the commits, for the body of each release (44b3576)
  • Secret scanning of the history (a60a97c)
  • The secret scan reads the scanner's exit code under bash -e (4ce539b)
  • The test values that look like credentials, listed for the secret scan (07996a8)
  • Advisories, licenses and sources of the dependencies, and the notices (e3c1f66)
  • An advisory of rsa, read and ignored with its reason; RSA signing is an entry (680dd3a)
  • An unmaintained proc-macro of the Tailscale fork, ignored with its reason (6060946)
  • The repository check finds a listener outside its allowance (241b681)
  • The code in one format: rustfmt, 120 characters, short items on one line (528bb64)
  • clippy gives no warning, and the gate checks the format and the lints (e892b0f)
  • Each repository check has a floor, and fails on an empty tree (cc386ce)
  • podssh-cli declares only the dependencies that it uses (188f327)
  • The container gets the tree that CI gets, and the gate needs AGENTS.md (8917417)
  • clippy 1.99 of the build image gives no warning (9966ed4)
  • The gate checks each crate on the minimum Rust that it declares (912acd0)
  • The record's checker finds a line number in plain text after a citation, and reads each bare :N (f8a94ca)
  • podssh relay spec checks the relay's document against the facts that podssh was built with (7e537b4)
  • Issue #33 is closed: its entries are done (0493f26)
  • The code carries no stop-sign markers (f32334c)
  • Code comments name what they mean, and a check keeps the rule (e3ea638)
  • A live TLS test tries a dropped connection again, and never a verdict (7c70aa7)
  • Dependabot's updates of the crates and of the checkout action (6e77829)
  • The line discipline runs only when it is selected and nothing below echoes (8d3f63d)
  • With IUTF8, the line discipline's cursor steps over characters and its screen moves by cells (a7648ff)
  • The line discipline reads the ESC O keys, and a lone Escape rings at its caller's idle tick (7e4a518)
  • The line discipline takes the terminal's width and draws a long line over several rows (cb94460)
  • Home, End and Delete move the screen's cursor, and the program's output goes around the line under edit (61eceeb)
  • podssh-ssh has an SFTP client, with a limit on each step (6483366)
  • podssh cp copies files over SFTP, verified by SHA-256 before they take the destination's name (2c1dc53)
  • podssh cp copies by exec when the server has no SFTP, raw through cat or through base64 (8848781)
  • podssh mv moves files: a rename within one server, else a verified copy and then the delete (62731d1)
  • podssh cp goes on after a broken connection, at the offset of the copy, in this run or the next (87058f5)
  • Each entry is tested natively until the release, by the operator's decision (fe8adfe)
  • podssh cp opens a new relay session before the relay's limits, and logs in as the first session did (bf42e84)
  • podssh scp and podssh sftp take the command lines of OpenSSH's (9841fa5)
  • The resumable layer: its records, offsets and handshake, and its client in podssh ssh node:// (f02812a)
  • The resumable layer keeps the bytes that are not acknowledged, 4 MiB each way, and the writer waits when they fill it (d70f88f)
  • A session to a node survives a lost link: the client resumes it on a new leg, and the node keeps it for 10 minutes (7797b2a)
  • The resumable layer's reader never waits for its writer, and a session's CLOSE is answered: a cut at any point loses no byte (a3b81d1)
  • A session to a node moves to a new link before the relay's limits, and the client warns an hour before its pair expires (fb228e9)
  • A node that lost its socket connects again on 409 until the resume deadline; a 409 at its first registration still ends it (fc01756)
  • The iroh road behind the feature iroh: an iroh endpoint set up as podssh's other roads, with the resumable layer's sessions over QUIC streams (8d88bdf)
  • The secret scan allows the made-up proxy credentials of the iroh road's tests (924ead3)
  • iroh tickets and node keys: podssh node --iroh prints its key and ticket, podssh ssh iroh:TICKET dials it, and a node lets in only the keys of its allowlist (d01b9cd)
  • A cache directory that is a file holds no key on Linux too (cce8dce)
  • The vi check of the Windows console job waits for vi's screen before it types (de847e1)
  • The iroh relays as a setting: the first relay of the list that answers /ping is the home relay, and the command line runs from end to end through a relay on the loopback (f77469d)
  • Throughput by one committed method: SSH through each road, 5 runs of 20 MiB each way a cell, measured on the loopback (8702dcf)
  • The race of the iroh road and the pair's road: the first far end that speaks carries the session, and the loser costs no connection to sshd (b58d23d)
  • The fault harness shapes the traffic: delay, jitter, rate, a cut with no Close, a pause that ends, and a client whose address changes (a22e3ec)
  • A copy stops at the size that its source had at the start: a source that grows ends the copy with 66, where the copy read on for as long as it grew (a6ef7ba)
  • The record's citations of docs/STATUS.md follow the row that T-267 added (b932993)
  • The record of CI's runs at 5557c62: the copy's new checks pass, and a mirror served each image that Docker Hub refused (b62d657)
  • A session ends when its link ends while it sends: the loop reads the channel's end while a send waits, and the relay stream's two tasks stop each other (3022d13)
  • The exit of M6: a session survives a stopped relay host, a new address of its client and a stall of 3 minutes, on the resumable layer and on the iroh road (94e3e6a)
  • podssh node --plain: each session carries TARGET's bytes as they are, with no resumable layer, for an operator that does not speak it (c982d27)
  • The record of CI's run at 94e3e6a: the gate's step m6 passed its 11 checks of the exit of M6 in the build image, in 692 s (78651e6)
  • podssh pipe A B joins two byte streams, as socat does, with no listener: stdio, fd:N and exec:CMD (0522c84)
  • podssh pipe reaches the roads: relay:, tcp:, ssh:, node: and iroh:; podssh proxy runs the pipe of stdio and relay: (b20de13)
  • podssh pipe unix-connect:PATH reaches a local socket: @NAME in Linux's abstract namespace, and on Windows an AF_UNIX socket or a named pipe (41507c9)
  • The newest resume of a session wins by the order of its handshake, not of its task: an older resume whose task starts late gives way (c48028b)
  • podssh ssh --persist: the shell runs in the server's tmux, and after a lost link podssh connects again and attaches the same session (9ae8d4a)
  • podssh pipe listens when asked: unix-listen:PATH and tcp-listen:[ADDR:]PORT, after the bind's probe, for one client or each in turn (a220c13)
  • podssh ssh -G prints the settings in effect, as OpenSSH's ssh -G does, and connects to nothing (97c1336)
  • The gate's run at a220c13: a node says online once the relay has its socket, a slow local side of the layer keeps its session, and the pipe's listener checks run before their directory goes (9460b4e)
  • The IRC client ends the CAP negotiation in answer to the server's ACK or NAK, not after a 001 that waits for it, and registers on a server that holds the registration until CAP END (c3eb09d)
  • The IRC client refuses a caller's text that would change its line: a CR, LF or NUL, or in a middle a space, a leading colon or nothing; a transfer refuses a bar in its fields, and keeps a peer's file … (93de442)
  • The IRC parser reads each field by its place in one list of parameters, so a command's last parameter parses with or without its colon, as ngircd, InspIRCd and ergo each write it (016baab)
  • The IRC line framing hands out the lines and the losses together, keeps nothing of a line with no end, and reads a line that is not UTF-8 as Latin-1 (4c3b456)
  • podssh ts makes one deadline from --timeout, and each wait for the first network map ends at its limit instead of waiting for ever (1ee321d)
  • podssh ts -W reads on after the end of stdin, so a reply after a request reaches stdout, and a closed stdout is a clean end (efee2fc)
  • podssh ts --jsonl writes the status as one JSON object, and --jsonl with ts -W is refused at parse, as under proxy (160773e)
  • The tailnet auth key is cleared from memory: podssh holds it in a buffer that zeroizes itself, expires its copy once the start returns, and the fork clears its own copies (patch 0015) (a9299c4)
  • podssh ssh -R and RemoteForward: the server listens, and podssh connects each connection that it takes to the target through the proxy (c0cdd2b)
  • interop: the -R refusal check asks for a port that sshd's PermitListen refuses, not port 22, which Docker lets a user bind (05d741e)
  • podssh ssh reads ~/.ssh/config, -F FILE and PODSSH_SSH_CONFIG as OpenSSH 10.3p1 reads them, and refuses Match and Include by name with the file and the line (28eab6b)
  • The tests remove their scratch directories, and the gate fails when a run of the tests leaves one in the temporary directory (84df12a)
  • User and RemoteCommand take OpenSSH's % tokens, and HostKeyAlias is lowercased, as OpenSSH 10.3p1 does (a5a6c6f)
  • The iroh road's test removes its scratch directory, as the gate's new check asked in CI (6192513)
  • Include in ssh_config is read as OpenSSH 10.3p1 reads it, with the system's file after the user's, and Match all and Match final all (d636c14)
  • The tests of pipe's listener and of --persist wait for the end of a stream before they read it, as a process ends before its reader has taken the last bytes (54b90c3)
  • The IRC client asks only for echo-message and znc.in/self-message, by name, once the last line of the server's list has come (36166be)
  • The IRC session knows its own nick: another user's JOIN and PART keep the channels, a KICK is read, the 005 lines add up, a reconnect starts anew, and a nick in use is tried again (ab7292d)
  • IRC file chunks are sized for the line that the server relays, with the sender's prefix, and the last acknowledgement names the short last chunk (e251072)
  • Each line of an IRC transfer waits its turn, so a server that closes a fast client lets the transfer through (c17e64f)
  • podssh ts checks each Tailscale mode through the proxy before the node starts, so auto falls through to relay, and an ephemeral node logs out at the end of the run (patch 0016) (0b6f4b8)
  • Each connection of a Tailscale node goes through the proxy, the DERP dial over WebSocket to the relay too, and podssh ts reads the environment's proxy as each podssh command does (patches 0017 and 001… (a3c196e)
  • A Tailscale node dials each dropped link again with podssh's backoff, knows a silent DERP link for dead, and podssh ts says each drop and each return (patch 0019) (323c1d7)
  • The secrets scan allows the made-up proxy credentials of T-103's tests (ade87b9)
  • The fork's own clippy passes with warnings denied, which no podssh build shows, and the prove script runs it (patch 0020) (d345b14)
  • The relay's refusal of a node key ends podssh ts with exit 77 and what the key needs, from the newest state of each link that the fork keeps (patch 0021) (291ad28)
  • Two tests of keygen, or of doctor, that run at once no longer share a scratch directory; the secrets scan allows patch 0020's line of context (dddcc8e)
  • The record's three citations of the doctor tests point at their lines again, which dddcc8e moved by seven (832149e)
  • A commit made without the record's remap is found against its parent, in CI and with cargo todo check --base; remap --base repairs it, and a changed file that is not text no longer stops the check (217f23b)
  • T-087 and T-088 are partial: the plan of the node's identity and of the channel between two podssh ends, with each decision and the corrections of their premises (f7cb5a6)
  • The identity of each end and the end-to-end channel between two podssh ends, as libraries of podssh-relay with no C; the iroh road runs on the shared key files, and shows a key by its fingerprint (T-0… (8e31960)
  • The end-to-end channel and the keys of each end run in each command of a road between two podssh ends: node, operator, ssh node://, ssh iroh:, pipe and the facade, with pins, an allowlist and --no-e2e… (a57b34f)
  • T-099 is partial: the plan of podssh chat on the roads, over the end-to-end channel (944448c)
  • The protocol of podssh chat between two podssh ends: bounded records, acknowledged messages, and files that move only once accepted, with their digests (T-099, partial) (b3092de)
  • The runner of podssh chat: a conversation over any stream, with files taken only once accepted and kept only whole, and no stall when both sides send (T-099, partial) (7aa955a)
  • podssh chat on the pair's road: one side waits as the node of a pair, the other reaches it, always over the end-to-end channel, with a file written only once accepted (T-099, partial) (e02f5c6)
  • podssh chat on the iroh road too, and T-099 closes: --listen NAME --iroh serves both roads with a ticket and an allowlist, chat iroh:TICKET reaches it (T-099) (94f6243)
  • The IRC client keeps alive with a PING that only it sees, never a PRIVMSG in a channel (T-098) (a2f86f3)
  • podssh chat --irc SERVER CHANNEL: chat in a channel of an IRC network, with TLS inside the relay stream unless --irc-plaintext names the risk (T-252, partial) (14f6cde)
  • Files over IRC between two nicks, accepted first and kept only whole, and podssh chat --irc --direct; T-252 closes (T-252) (8cf2587)
  • The tests of chat --irc remove their scratch directories, which the gate's steps ssh, iroh and ts found left at 8cf2587 (T-252) (c29fa82)
  • podssh ssh never ends as a success with no exit status: a closed stdout waits 5 s for the status, and -N that the server ends is 255 with its words (T-026) (bc59415)
  • accept-new refuses a key that it cannot verify, as a user known_hosts that cannot be read hides what is recorded there, and a key that cannot be recorded is said to hold for this connection only (T-02… (b657023)
  • Two runs that meet a new host at once record its key once, under a lock that refuses no reader, and a second key of the type is refused as changed (T-029) (2a436bc)
  • podssh ssh --host-key-fingerprint SHA256:B64[,...]: the destination may present only the keys that it names, also under accept-new, and none is recorded (T-031) (cafcdb4)
  • podssh ssh --direct fails a write that makes no progress for 60 s, the relay leg's limit, and a lost session says why (T-227) (f502fba)
  • The gate's interop no longer hangs: T-026's sshd took port 2205, which interop-cp.sh uses, and its clients had no time limit (T-026) (4dd52f8)
  • PODSSH_CACHE_DIR names the cache's directory, none keeps no file, and each other place comes from the environment, the temporary directory's fixed places last (T-243) (e74b532)
  • tests/status.rs removes each scratch directory, which the gate's steps found left at e74b532; T-278 closes on a green run on the named runners; GitHub #36 is closed (T-243, T-278, T-227) (981b8fc)
  • podssh ssh tries a session again when the relay dropped it before any request reached the destination, never after (T-025) (33c9a31)
  • podssh checks host certificates against the @cert-authority lines of known_hosts, as OpenSSH does, and falls back to the plain key when no line names the CA (T-027) (a1d32e0)
  • AGENTS.md and README.md list podssh agent among the commands that work, and README.md lists podssh pipe (3408de9)
  • podssh ssh -A forwards the agent to the destination only, off by default, with -a, ForwardAgent and ${NAME} in the agent paths read as OpenSSH 10.3p1 reads them (T-036) (fa61558)
  • tests/agent_cli.rs ends the agent with SIGTERM and checks its exit and its socket, as CI at f7d5640 found that the guard's SIGKILL left both on Linux (T-034) (97146aa)
  • podssh ssh -L and -D listen here once the bind and the listen succeed before anything connects, with OpenSSH's forms and addresses, SOCKS4, 4a and 5 for -D, and ClearAllForwardings (T-038) (5fb9c1e)
  • Connection sharing on Unix: podssh ssh -M serves OpenSSH's control protocol on a socket of mode 0600, -S runs through a master, and -O speaks to it; podssh and OpenSSH masters and clients work with ea… (2828281)
  • podssh ping times each step to each relay host and matches each WebSocket ping to its pong; with a destination it adds the login, the echo through cat, and the bytes down and up, each remote command n… (24f3e2a)
  • podssh relay status with no NAME reads each relay host's /health, info reads the pool and the limits of /relays.json, and trace has the relay dial a target and read its first line, the token in its he… (615c415)
  • tests/ssh_exit_status.rs holds podssh's stdin open, so that the remote writes until podssh's own end of input when its stdout closes, as CI at 615c415 found that an end of input sent at once could sto… (0d3d13a)
  • TLS 1.2 after TLS 1.3, for proxies that intercept TLS: ECDHE with AES-GCM or ChaCha20-Poly1305 on podssh's own provider, each suite checked against OpenSSL's s_server; ECDSA with either hash on either… (a7c1394)
  • tests/tls12.rs makes its certificates once into a directory that goes at once, and each test writes them into one of its own, removed when it ends, as CI at a7c1394 and 73f910b failed in its step libs… (a06a81e)
  • tests/tls12.rs names the type of its files, which clippy's type_complexity refused at a06a81e (dab5669)
  • podssh reaches the relay through a SOCKS5 proxy too: socks5:// and socks5h:// in the proxy variables, the relay's name as the address type 3 so that no DNS is needed, the user and password of RFC 1929… (ff8486d)
  • The entries of podssh serve that build on the held T-107 to T-112 are parked with a start condition, as T-150 is (T-114, T-115, T-116, T-119, T-120, T-122, T-123, T-124), and the start of T-250 and T-… (39e085b)
  • crates/podssh-cli/src/man/facts.rs keeps to 500 lines: its tests move to man/facts/tests.rs, with the citations of their lines, as CI at ff8486d found 501 lines after T-070 (385486f)
  • Fuzzing: 18 cargo-fuzz targets in fuzz/, one for each parser of a peer's or a file's bytes, each with checks past the absence of a panic, run by scripts/fuzz.sh on glibc with the address sanitizer and… (5a88857)
  • The secret scan allows the proxy URL with a made-up user and password at proxy.example that T-070's test of podssh status holds, as the workflow secrets found it unknown at ff8486d (e499c7b)
  • On Windows a session that --persist attaches again no longer waits for a key: podssh asks once whether stdin is a terminal, before the input's task reads it, as std's question for a pipe waited for th… (b81480d)
  • A scored interop harness: each check of the harnesses prints VERDICT ID TEXT with an id that does not change from run to run (scripts/interop-lib.sh), scripts/interop-baseline.txt names the 322 ids wi… (72ca309)
  • Resource limits, stated and tested: docs/architecture.md lists each bound of memory and of time with its constant and what podssh does past it; known_hosts is read up to 16 MiB, in both of its reads, … (3214fa1)
  • The relay hosts of a run overlap (GitHub #30): --relay-failover and PODSSH_RELAY_FAILOVER choose staggered, the default, where the next host starts when the one before it has not opened within 2 s or … (4cfbd5f)
  • podssh agent keeps passwords and passphrases (T-228): add-password [USER@]HOST[:PORT] and add-passphrase FILE take the secret from stdin, the terminal or SSH_ASKPASS, never from the command line, into… (88493e3)
  • The console checks wait for less and top to draw before they type (T-283): at 88493e3 the job windows failed conpty.less, as G and q reached the shell's line discipline before less had set its modes a… (ff75425)
  • RSA user keys sign through aws-lc-rs, never the rsa crate (T-257): a key file's RSA key is read once into an aws-lc-rs key pair, its CRT exponents computed in constant time with crypto-bigint, and sig… (42b9270)
  • podssh agent refuses a key for a confirmation of each use (T-284): russh 0.64.1's agent server keeps the constraint of ssh-add -c and signs with the key unasked, never calling the agent's confirm, so … (945098b)
  • A login goes on after an agent fails to sign (T-285): once the server took the agent's key, russh waits for a signature and drops each other request, so the next key's request got no answer and the lo… (908374d)
  • cf://HOST reaches a service that cloudflared publishes (T-264): podssh ssh cf://[user@]HOST and podssh proxy cf://HOST open the WebSocket to wss://HOST/ that cloudflared access tcp opens, with its upg… (262c7c0)
  • Two tests of the record's interop no longer share a scratch tree (T-286): each tree was podssh-todo-PID-NAME, so the two tests that score a run, which run at once, used one directory, and the drop of … (32cae31)
  • On Windows the owner and the access list of a private file are checked (T-274): one function, podssh_relay::cache::closed, reads the opened file's security descriptor for the cache, podssh's own files… (3a78cff)
  • The help groups the commands by purpose (T-013): podssh --help and the manual's Commands list the 18 commands in eight groups, Connect, Copy files, Keys, Check this host and the path, The reverse road… (bdbe658)
  • podssh keygen -p and -c change the passphrase and the comment of a key (T-018): -p asks for the old passphrase, then for the new one two times, and -c takes -C or asks, as ssh-keygen does; -P '' is fo… (a0757ed)
  • On Windows a new key of podssh keygen is closed to others (T-288): the key took the access list of its directory, so each principal that the directory let in could read it, and OpenSSH for Windows 10.… (fe19445)
  • An encrypted key of each format is asked for (T-287): russh found no encryption in a key of PKCS#8 or of PuTTY, nor in a PEM key of another cipher than AES-128-CBC, and read a decrypted PEM key only a… (fbb9b94)
  • The tests of key_file are formatted as rustfmt formats them (T-287): the gate's step lint failed at fbb9b94 on their format, which cargo fmt had not been run on; cargo fmt over the gate's packages now… (f6b7676)
  • podssh keygen -F, -R and -H find, remove and hash the lines of known_hosts (T-019), with the lines, messages and exit codes of ssh-keygen: beside that of OpenSSH for Windows 10.0p2, on copies of one f… (63cad33)
  • podssh keygen -Y signs and checks SSH signatures (T-020), as ssh-keygen -Y does for git's signing: sign writes FILE.sig, never over one, or standard input to standard output, through the agent when it… (b37abb3)
  • The test data of signatures and certificates keep their bytes on a checkout (T-020): with text=auto, the Windows runner checked out the signed file with CRLF, and the check of OpenSSH's signature over… (6078e57)
  • podssh keygen -s certifies user and host keys with a CA, and -L prints a certificate (T-021), with the lines and messages of ssh-keygen: -I the key id, -n the principals, -V its validity (+52w, or FRO… (8290fe1)
  • podssh keygen -e, -i and -m convert key formats (T-022), as ssh-keygen does: -e prints a public key as RFC 4716 (the default), PKCS8 or PEM, byte for byte what OpenSSH's -e writes apart from the comme… (e85e6d2)
  • Each hop of a -J chain checks its own host key, under its own name (T-030), now in one function, hop_key_name, with its test: a jump hop on port 22 and on port 2222, and the destination with and witho… (b0177cf)
  • A hop of -J or ProxyJump takes the ssh_config blocks of its own name, as OpenSSH's jump host does (T-290, a P2 defect found in T-030): its HostName, Port, User, IdentityFile, HostKeyAlias and the sett… (3e42773)
  • podssh ssh --sudo and --su run a remote command as root, with the password asked here, on the terminal or through SSH_ASKPASS, and never taken from the command line (T-032). --sudo sends sudo -S -k -p… (cd000c2)
  • podssh ssh --record FILE keeps what a session showed, with its timing, as asciicast v2, and podssh play FILE shows it again (T-033): the header, an o event for each output and an r event for each new … (e58ebcd)
  • podssh ssh -X and -Y forward X11 to the display that DISPLAY names (T-037): the server is given a spoofed cookie of the same length in x11-req, and for each x11 channel that it opens podssh connects t… (f2631b4)
  • The gate's checks of --record and podssh play (T-033) run podssh ssh again: at e58ebcd they ran podssh ping and failed with "unknown flag '-t'", as scripts/interop-ping.sh, which the faults harness so… (f6af943)
  • podssh ssh -W /PATH reaches a Unix socket on the server (T-040), as OpenSSH's -W /PATH does, where it was refused: the server opens it as direct-streamlocal@openssh.com, and through a control master t… (5819133)
  • The gate's check of podssh ssh -X (T-037) tells the Xvfb's refusal from podssh's: at f2631b4 the Xvfb of the box refused the untrusted cookie of xauth that -X put in place, with "Invalid MIT-MAGIC-COO… (02093b5)
  • Each forward of a session counts what it carries, and the escape ~# lists them (T-041): for each -L, -D, -R and -W, as the user wrote it, its connections, those open and those that failed, and its byt… (8d2187c)
  • The session of a control master's client lists the forwards with ~# (T-041's repair): at 8d2187c the gate did not build on Linux, as crates/podssh-ssh/src/mux/msession.rs, which Unix builds alone, mat… (f80e7f3)
  • podssh ssh --persist -N keeps the forwards through a lost link (T-042): no tmux runs, and after a loss, the server's own close too, podssh connects again as --persist does and asks for each -R again, … (4b2f621)
  • The gate's checks of ~# and of -v -W (T-041) test podssh again: at f80e7f3 both failed for their harness. stdio.counts: wait_ports took the one connection that the echo server of port 2215 accepted, s… (ec7f018)
  • The gate's runs of podssh in the background end when they are killed: a function run with & is a shell of its own, and kill ended that shell alone, so the podssh of T-035's check held OpenSSH's port 2… (d0167b9)
  • Match in ssh_config is read as OpenSSH 10.3p1 reads it (T-045): host (the name after HostName), originalhost, user, localuser, tagged, command, sessiontype, version, final and canonical, each with ! a… (a85d3d0)
  • podssh config import ansible FILE prints a Host block of ssh_config for each host of an Ansible INI inventory (T-047), and a summary on stderr; it writes no file. The inventory is read as Ansible read… (99743e6)
  • A settings file states podssh's own relay settings once (T-048): RelayHost, RelayAddr (whose lines add up), RelayFailover and CaFile, below the flags and the variables and above the defaults. It is th… (fab5b7f)
  • podssh ssh --result-file FILE writes the result of a run as one JSON object (T-054), at its end and on each path, also when it failed before it connected: schema, exit, the remote status or signal (it… (33d3a0c)
  • podssh mcp serves the commands of podssh as tools for an agent (T-055): a Model Context Protocol server on stdin and stdout, one JSON-RPC message on each line, for the revision 2026-07-28, whose reque… (f0b6239)
  • A log of the sessions of this host, when the user asks for it (T-056): PODSSH_SESSION_LOG=1 (or yes) keeps a JSON line for each run of podssh ssh and podssh proxy that named a destination, in sessions… (db7264f)
  • A relay host that failed recently is tried last, also in the next run (T-059): a host that failed with an error that another host could repair, or that said nothing while a host after it opened (the r… (e709c0c)
  • T-062 waits for the operator (Q42): whether the relay's backpressure close operates needs a target that sends much data fast through its forward path, and from this host no allowed target does: railwa… (19b3854)
  • A node offers several named targets, each with its own grant (T-089): podssh node NAME [TARGET] ROUTE=TARGET... serves each TARGET under its route with one pair and one node, and an operator names one… (d1ef0d1)
  • Finding a node by name with no payload leak (T-090): a label of the user's own, mapped to the newest pair kept under it, and the node's key pinned by label, as T-083 and T-087 built them; this proves … (715eddd)
  • State which terminal sequences podssh reads and which it passes unchanged (T-130): the escapes are one table, ESCAPES, which the input and ~? read; docs/terminal.md and the manual's note of ssh list w… (394925f)
  • Measure which servers act on the signal request for Ctrl-C with no remote pty (T-131): a test logs in with podssh's client, runs a command with no pty, sends signal INT after 1 s, and reads what ends … (579cb5d)
  • Compare the Windows console handling with csshw's, and measure podssh in a pseudo console (T-132): a ConPTY of the test process (tests/conpty_harness) runs podssh against the test's own SSH server, wh… (117589b)
  • A byte of output that is not UTF-8 no longer ends a session's output in a Windows console (T-294): Rust's console writer refuses such a byte, and podssh took the refusal for a stdout that is gone, so … (ae0240e)
  • Ctrl-Break no longer leaves the Windows console raw (T-295): Ctrl-Break, a closed window, logoff and shutdown end podssh through the console's default handler, which runs no destructor, so a session w… (fe66d2e)
  • Pipelined SFTP (T-140): the reads and the writes of a copy go with requests in flight together, up to 64, each of the server's size, never more than 512 KiB in flight, the window that podssh gives a s… (3fbdce0)
  • Parallel transfer in chunks (T-141): cp and mv --parallel K copy a file of more than 8 MiB as chunks at fixed offsets, K at once (1 to 16; default 1), each over an SFTP session of its own, so a channe… (d6fab71)
  • The bound of the bytes in flight that T-141's tasks share (T-141): Pipeline gains in_flight, which depth() takes with the window, as d6fab71 uses; that commit left this half out, and CI failed to comp… (789dd5d)
  • Delta copy, only the blocks that changed (T-142): cp and mv --delta, over an older version of the same file on the other side, send only the blocks of 1 MiB whose SHA-256 differs. One command over exe… (e6d17bb)
  • Copy directories (T-143): cp, mv and scp -r copy a directory and what it holds, depth first with lstat, 64 levels at most, each file as one copy goes (a temporary name, the digest, the rename, its con… (1622eba)
  • Make the target a mirror with cp -r --delete (T-144): what the copy's root holds and the source lacks goes, a directory after what it holds, at the end of the run and only when each copy of the run su… (1f9000b)
  • Progress, cancellation and a bandwidth limit for copies (T-145): on stderr, when it is a terminal and -q is not given, one line that a carriage return rewrites 4 times a second at most (the name, the … (ebde017)
  • The bucket's test starts the bucket itself (T-145): CI at ebde017 failed it in the three gate jobs, as the test made its bucket, then read the clock again, and the time between gave the bucket bytes, … (b03c8d5)
  • Keep a copy's metadata (T-146): -p keeps the access and the modification times of each file, up, down, within one server and on the exec road (chmod, touch -t in UTC and chown before mv; stat down), a… (9786647)
  • Park T-159 behind podssh serve: a shell that outlives the client lives in the server, and the operator holds T-107, T-108, T-110 and T-117 (Q32), so the entry gets a start condition as T-114 has, and … (9114363)
  • The test of -p is formatted as rustfmt formats it (T-146): an edit after cargo fmt left a line of cp_meta.rs without a space, which the gate's lint step finds (4aa8224)
  • Copy into the destination itself with cp --inplace (T-147): no temporary name and no rename, so the file keeps its inode, its other hard links and each program that holds it open see the new bytes, no… (d56d316)
  • Park T-160 behind podssh serve: its invariant, no prediction while the pty's ECHO flag is off, needs the far end's pty to report that flag and the offset of the input, and prediction is only for a pod… (3a4055d)
  • Edit a far file with podssh edit HOST:PATH (T-149): the file comes down as cp copies one, into a private directory of mode 0700 in the cache as a file of mode 0600 that keeps its name or extension, wi… (dfad42a)
  • Detach and attach again (T-158): a far end that keeps shells names keep.v1 in the layer's greeting, and only then is ~d an escape: podssh asks the far end to keep the shell (env detach@podssh NAME on … (61796d8)
  • Park T-161 behind T-159: each step measures what a client gets when it attaches to a shell that a far end kept (the ring replayed from a boundary, the modes, a snapshot), and no far end keeps a shell … (9caa73b)
  • The quick tunnel and the functions of Mosh, read and written down (T-170, T-171): docs/design.md section 2 gives the protocol and the ports of a Cloudflare quick tunnel, read in cloudflared at bf4f502… (ff1718d)
  • ZMODEM in a terminal session (T-148): in a podssh ssh session with a pty and a local terminal, the output is watched for the start of lrzsz's sz (rz\r, then the ZRQINIT header) and rz (ZRINIT). When s… (18db4c8)
  • A roost: podssh next to a standard sshd (T-166): podssh node NAME [TARGET] --sshd is a node in front of a standard sshd (TARGET defaults to 127.0.0.1:22), so a normal server gets the resumable layer a… (8c05b5e)
  • Start from a standard sshd, then move the session to a better road (T-167): podssh ssh --upgrade DEST logs in as each run does, asks the server for podssh --version, and when a podssh answers runs a t… (c6ea9cd)
  • UDP over the relay (T-168): podssh node NAME udp:HOST:PORT serves a UDP service: each session is one flow of datagrams from the node's host, a socket of port 0 connected to the target that ends with i… (cacae2a)
  • The note of podssh pipe names a Unix datagram socketpair (T-168): the manual's check reads AF_UNIX as a variable that ENVIRONMENT does not have, and failed the unit tests of the manual (4d5a353)
  • Multipath TCP on the direct road (T-172): with --direct and PODSSH_MPTCP=yes, the first hop's connection asks Linux for an MPTCP socket when no proxy is in the way and /proc/sys/net/mptcp/enabled is 1… (b9d8ffe)
  • Desktop streams and Telnet through proxy and pipe (T-179): README's "Other TCP protocols" says the three forms: OpenSSH listens and podssh proxy carries its session (ssh -N -L with podssh proxy as the… (3224a88)
  • A serial: address for podssh pipe (T-181): serial:PATH[,BAUD] opens a character device that is a terminal with O_NOCTTY and O_NONBLOCK, holds it alone with TIOCEXCL, and sets it raw at BAUD (115200 wh… (2eb07e1)
  • USB/IP through podssh pipe, a recipe with no driver (T-182): README's table "Other TCP protocols" gets a row for USB/IP and the recipe below it: pipe --keep-listening tcp-listen:127.0.0.1:3240 to ssh:… (3c54294)
  • Run one command on many hosts: podssh each (T-183): podssh each [OPTIONS] HOSTS [--] COMMAND runs the command on each host of a comma list, --parallel at once (8; 64 at most), each on ssh's road and S… (bdac99a)
  • Host groups and brace expansion of host names (T-184): the host list of podssh each takes bash's braces (web{1..3}, {01..10} with its zero padding, a{b,c}d, nesting, letters and a step) and @GROUP fro… (a38421b)
  • The desktop's rate in the gate needs a font (T-179): the first run in CI (3224a88) passed 6 of the 7 desktop checks, whose lines docs/STATUS.md now gives, and failed desktop.vnc.rate: each viewer's co… (cad2885)
  • A terminal oracle (T-200): the tests read screens, not bytes, through a model terminal, the vt100 crate (pure Rust, a dev-dependency only): the line discipline after each key of 1100 runs of up to 48 … (4168a3e)
  • The gate's lint at Rust 1.99 (T-184): clippy's needless_borrows_for_generic_args refused the two map_err(&fault) of hosts.rs, a closure that only borrows and so is Copy; it is passed by value. Rust 1.… (9dfa2d0)
  • The gate's run at cad2885 in the record, and the drafts that wait (2026-10-13): the step release passed 478 checks, so docs/STATUS.md and T-179, T-182 and T-183 give the desktop's rate (idle 0 bytes a… (0f1908c)
  • AGENTS.md: drafting agents (the operator, 2026-10-13): section 2 says how subagents draft entries in worktrees of their own, never building, while the main session merges one draft at a time in the or… (905f92c)
  • A test of T-042 that depended on time: a forward refused for the whole time failed once in the workspace's run (2026-10-13), as on a loaded host one ask took more than 260 ms and the limit of 300 ms h… (24b9f6e)
  • Property tests for the state machines (T-202): proptest 1.11, no default features, in the tests of podssh-ws, podssh-relay, podssh-ssh, podssh-core and podssh-terminal, 256 inputs a property: WebSocke… (1bd66e7)
  • Kept output starts at a boundary of the terminal grammar (T-221, GitHub #31): a sans-IO tracker in podssh-terminal finds where a stream of output may start (ground, escape, CSI, OSC and the control st… (61e55d1)
  • Ctrl-C with no remote pty sends signal INT to the command (T-293): in a session of a command or a shell with no pty, the first Ctrl-C sends the request and waits 2 s for the command's end, whose signa… (d0eeaf3)
  • TODO/PROGRESS.md: a checkpoint of the drafts (2026-10-13): T-202, T-221 and T-293 are merged; T-225 is the next merge; a row being drafted in a new worktree is found with git worktree list, its last c… (69f70c7)
  • TODO/PROGRESS.md: the branches of the drafting agents still at work (T-192 to T-197, T-189 to T-191, T-229), so that a later session finds them (e4bcd06)
  • TODO/PROGRESS.md: T-195 and T-189 are drafted (PODSSH_ERROR_PROGRAM, podssh health), on e4bcd06 (79369c6)
  • TODO/PROGRESS.md: T-229 is drafted (hardware keys), on T-289's branch (0c1b50f)
  • TODO/PROGRESS.md: T-193, T-197 and T-192 are drafted (podssh job and podssh run) (9d1d024)
  • TODO/PROGRESS.md: T-190 and T-191 are drafted (podssh containers; LocalCommand and expect rules); each draft of the table is whole, and the next merge is T-225 (b64664a)
  • Each exit code of the interop gate against OpenSSH's own client (T-225, GitHub #34): scripts/interop.sh runs OpenSSH's ssh first with the same arguments for the 25 cases of the exit matrix and of the … (e8bec97)
  • The prompt gate that no command called is gone (T-232): gate_prompt, PromptSite, force_interactive and Attachment::ForcedInteractive, with their tests; the module says what it holds and that podssh-ss… (1547083)
  • The help's --help is a row of each command's OPTIONS block (T-235): 8 spaces in, as each long option with no short form, its text in the column of the other rows, and the last line; it started 4 in wi… (3ed3e54)
  • The frame decoder refuses a length that is not in the minimal form (T-242): a 16-bit length below 126 and a 64-bit length below 65536, as RFC 6455 section 5.2 requires, in either direction, before the… (5ad7b31)
  • -A binds the forwarded agent to the server's host key (T-279): before the server's first byte on each agent channel podssh sends the agent session-bind@openssh.com with the host key, the session ident… (922f1aa)
  • The secrets scan allows the test keys of russh 0.64.1 in vendor/russh (T-279): TruffleHog's run at 922f1aa found 13 private keys in russh's own tests, two of which it could not verify, and so failed; … (9d9d692)
  • The escape ~C adds and stops the forwards of a running session (T-291): in a session with a pty, ~C reads OpenSSH's command line from the session's keys; -L, -D and -R add a forward on the session's c… (80bfc02)
  • A new entry, T-308: Dependabot's docker job fails at each run (2026-10-09 twice, 2026-10-13): Docker Hub answers with its usual token challenge, and GitHub refuses the pull request that moves the box'… (31d79d3)
  • TODO/PROGRESS.md: the id kept free for T-302's new entry is named without an id that the index does not have yet (b4f0538)
  • A forward of -R with a named port is podssh's from its request on (T-042): a test of --persist failed once in a run of the iroh suite, as the server opened a channel for the forward as soon as it took… (97d7009)
  • The iroh road through a SOCKS5 proxy (T-280): iroh-relay 1.3.0 is carried as vendor/iroh-relay, the published crate with one patch (vendor/patches/iroh-relay/0001-socks5-proxy.patch, file for file) by… (8290ae0)
  • podssh ts through a SOCKS5 proxy (T-281): the fork's patch 0022 gives its one dialer SOCKS5 (RFC 1928 and 1929, the host's name with the address type 3, one more try with an address on reply 8), so th… (125477e)
  • podssh keygen -Y with certificates (T-289): -f KEY-cert.pub signs with the certificate and KEY or the agent's key, and a cert-authority line of allowed signers allows the signature of a user certifica… (c7c5aa6)
  • Hardware keys, FIDO2 sk- keys (T-229): podssh keygen -t ed25519-sk and -t ecdsa-sk make a key in a device, and the login and podssh agent sign in it, after a probe at run time: CTAP2 over /dev/hidraw*… (51a0d88)
  • cp, mv, scp and sftp reach a node of a pair (T-296): an operand node://[user@]NAME[/ROUTE]:PATH, and sftp's destination node://..., reach the node as podssh ssh node:// does, through its pair and the … (b20ffa1)
  • sftp's get -r and put -r copy a directory (T-298): with -r or -R, and each get and put after sftp -r, a batch copies a tree with the tree copy of cp -r over the batch's session, empty directories and … (c32a915)
  • cp --parallel K copies several small files at once (T-297): with K above 1 and several files, up to K go at once over the one connection, each over an SFTP session of its own and its own side file; a … (9f86503)
  • The test server's state of a connection in a file of its own, and a copy's temporary file named before the server makes it (T-297): ssh_harness/mod.rs had 507 lines with T-297's hooks, past the rule o… (7cf0e45)
  • Snippets and argument templates, shown before they run (T-187): the [snippets] table of the settings file holds commands with {{host}}, {{user}}, {{port}} and {{1}} to {{9}}; podssh ssh --snippet NAME… (93a3fa7)
  • A host picker when podssh ssh gets no destination (T-188): with stdin and stdout both terminals and no destination, the literal Host names of ssh_config and its Includes, numbered; a number logs in to… (4130854)
  • Hand a failure's report to a program that the user names (T-195): with PODSSH_ERROR_PROGRAM set, a run of podssh that itself fails starts that program with no shell and no argument and writes one JSON… (ca9e8f0)
  • The health of the far host: podssh health (T-189): podssh health [user@]host logs in and runs one fixed script that only reads, and prints the far host's load and CPUs, the busy share of the CPUs, its… (ffc3400)
  • Containers and pods as destinations: podssh containers (T-190): one login runs one sh -c script that probes the far PATH for docker, podman and kubectl and lists what each has, one line a container wi… (026db5a)
  • Expect rules, and LocalCommand (T-191): --expect TEXT --send KEYS drives a session with a pty, each rule in order against its output with --expect-timeout, the session's own input held until the last … (9b6dda2)
  • The secrets scan allows three made-up proxy URIs of tests: TruffleHog's runs from 8290ae0 to 9b6dda2 failed on a:~~~ at the loopback in crates/podssh-iroh/tests/relays.rs (T-280, a password that iroh'… (3ad3203)
  • sync uncommited files (d1c5bd1)
  • A cloud session made ready in one command, and the defects that its first run found (T-310 to T-315; T-185 measured): scripts/cloud-setup.sh starts dockerd, sets Podman up for a host with no systemd a… (396e2c4)
  • The first beta made ready, v1.0.0-beta.1 (T-309): the version 1.0.0-beta.1 in Cargo.toml and both lock files, and the SSH banner SSH-2.0-podssh_1.0.0_beta.1, as RFC 4253 allows no - in a software vers… (f5e06ca)
  • no_proxy matches the addresses inside a block (T-316): an entry ADDR/BITS, IPv4 or IPv6, keeps each address inside it off the proxy, as curl, Go and Python's requests read it, and an IPv4 address writ… (5515730)
  • The research of 2026-10-30 in the record: T-299 has eight corrections to the section of docs/design.md on the quick tunnel and the plan of its measurement in GitHub Actions; T-300 and T-301 a Correcti… (ad6fd4c)
  • The release workflow publishes from a run by hand too (T-309): this cloud session's git pushed main and was refused the tag v1.0.0-beta.1 (HTTP 403, five times), so a run by hand with the input publis… (5c8d423)