say-hi and the alternatives

This project beside its neighbours: some may suit you better, and some were instrumental in this one.

Contents

The problem being solved

You have a shell you have spent years tuning, and you spend your day on machines that are not yours: production boxes, a colleague’s server, a jump host, a container that will not exist in an hour. There you get sh-4.4$ and no ll.

Install your config there. Dotfile managers — chezmoi, yadm, GNU Stow, dotbot, rcm, homeshick. Excellent, and say-hi does not compete with them: they assume the machine is yours, that you’ll be back, and that leaving files behind is fine — wrong for a shared production host, a box you touch once, or a container. The edge blurs (chezmoi’s --one-shot, devcontainers cloning a dotfiles repo), but both need the target to reach your repo over the network, both leave files behind, and neither does anything per-session.

Carry your config with you, per session. Ship it over the connection, use it for that session, get out. That is say-hi’s family, and everything below is a member of it.

Not the same thing: terminal emulators that help with ssh, like kitty’s ssh kitten, which solve the adjacent terminfo / shell-integration problem. If your pain is “backspace is broken over ssh”, that is the fix, and it composes with say-hi — which handles the terminfo half itself, swapping a TERM the target has no entry for to xterm-256color (HI.22).

The direct alternatives, side by side

  say-hi sshrc xxh kyrat sshdot
Written in POSIX/bash shell shell Python bash shell
Client needs bash 3.2+, base64 (or openssl) bash, ssh a Python install (pip/pipx/conda) or the portable binary bash ≥ 4.0, GNU coreutils shell, ssh
Target needs base64 (or openssl); bash for the full session openssl (its base64), tar, bash Linux x86_64 only shell shell
Target OS Linux (glibc + musl), macOS/BSD, Windows via WSL/Git Bash broad Linux x86_64 Linux, macOS broad
Installs on target nothing nothing a portable shell + plugins under ~/.xxh nothing nothing
Cleans up on exit yes, automatically yes, on exit (a hard kill leaves it, as with hi) not by default (+hhr removes it on disconnect) yes, automatically yes, on exit
Size ceiling no argv cap (stdin); CI holds a 64KB gzipped budget ~64KB and the server may block you large — it uploads whole shells small none (that is its point)
Non-ssh targets docker, podman, nerdctl, finch, nomad, k8s no no no no
Can give you a shell the host lacks no no yes no no
Maturity pre-1.0, packaged original gone from GitHub; cdown’s fork maintained mature, active quiet since 2020 quiet since 2015

Tool by tool

sshrc — the ancestor

say-hi is a fork of sshrc (via cdown’s and danrabinowitz’s lines), and the core idea is unchanged: tar your config, base64 it, hand it to the login shell, source it on the far side. Links here point at cdown’s fork, the maintained continuation, which keeps the design (64KB argv ceiling included).

Where sshrc still wins: smaller and simpler, which counts in something that runs on every host you touch. If you just want your .bashrc and .vimrc over there, sshrc does it in a fraction of the code.

Where say-hi went further, beyond the table’s rows:

  • Cleanup, proven for the dropped link. tests/targets/ssh_disconnect_test.sh freezes a live session until sshd reaps it and checks the tree is gone, not only after a clean exit.
  • A designed session, not copied files. Header, hashed per-host colors, a git prompt, aliases, editor configs — degrading in defined tiers when the target cannot support all of it.

xxh — the one that solves a harder problem

xxh uploads a portable build of the shell itself, so you can use fish or zsh on a host that has neither.

Where xxh wins outright: that capability. say-hi cannot give you a shell the target lacks — its no-bash ladder (fish > zsh > dash > ash > sh) picks the best of what is installed and says so. xxh’s plugins can also ship whole frameworks, where hi’s extensions/ (HI.59) is shell lines.

Where say-hi wins, beyond the table’s reach and weight rows: no architecture or libc tie. Anything with sh and base64 is in reach, and CI lands sessions on musl, macOS, the BSDs, and Windows (COMPATIBILITY.md) where xxh’s shells are x86_64-Linux builds.

kyrat — closest in spirit

kyrat is the nearest neighbour: a bash ssh wrapper, base64+gzip through the command line, cleanup on exit, KYRAT_SHELL to pick bash/zsh/sh. If you don’t use fish, kyrat is a lighter alternative — ssh only, and bash ≥ 4.0 on the client rules out macOS’s stock bash, but simpler.

sshdot

sshdot is sshrc without the size limit, achieved by not squeezing through the command line. Narrower than say-hi: it solves the one problem it names.

homeshick — the same constraints, the opposite answer

homeshick is a git dotfiles synchronizer in bash whose constraints look most like say-hi’s: “provided that at least Bash 3 and Git 1.5 are available you can use homeshick” — no Ruby, no Python, no root. It answers the other half of the problem, symlinking a cloned repo’s home/ into $HOME and keeping the two in step.

So it is not a competitor and is not in the table. It is the tool for a machine you own and will come back to: the checkout and symlinks stay, and the next login is configured with no client involved. The failure modes are mirror images: homeshick on a production box you touch once leaves a ~/.homesick and an edited rc file for the next person; say-hi on your own laptop re-sends a payload every session for what a symlink gives for free. The two compose — install say-hi permanently on that box (scripts/install.sh) and let homeshick manage everything else.

Adjacent tools, and how they compose

None of these are alternatives — they touch the same session from a different side.

  • mosh / Eternal Terminal replace ssh as the transport. hi’s ssh path is two calls multiplexed on one OpenSSH connection, which neither of them is, so hi cannot ride them. What works: install say-hi permanently on the target, then mosh in.
  • Warp’s SSH extension and “Warpify” attack the same pain from the terminal side: a persistent remote component under ~/.warp* plus a hook line in the remote’s rc files. It ships Warp’s features, not your config. The two coexist — say-hi writes nothing into the remote’s rc files.
  • chezmoi/yadm/GNU Stow as the overlay’s keeper. Keep ~/.config/say-hi/ in your dotfile manager: the manager versions it, hi ships it to every target per session. SETTINGS.md covers symlinks and who owns settings.sh.

What actually makes say-hi different

Two things; the rest is degree, not kind.

1. It is not an ssh tool. Every alternative above is an ssh wrapper. hi resolves a name through a ladder — ssh host, container (docker, podman, nerdctl, finch), nomad allocation, kubernetes pod — and gives the same session on whichever it finds. hi web-1 is your shell whether web-1 is a Host in ~/.ssh/config or a pod in the namespace your kubectl points at. Nothing else in this space does it.

2. It degrades in stated tiers rather than failing or lying. The compatibility tables answer two questions — can hi land a session here at all, and what shell do you end up in — and mark every cell exercised by a suite, expected, reduced, or decided against. A target with no bash gets aliases, a colored prompt, and a warning; a Windows OpenSSH host with no POSIX shell gets a plain PowerShell session rather than an error.


This site uses Just the Docs, a documentation theme for Jekyll.