shpool

repository·master·Indexed 23 days ago

https://github.com/shell-pool/shpool

A session persistence tool designed to provide persistent remote shell sessions while maintaining a native terminal experience. Unlike multiplexers, shpool focuses solely on persistence and relies on the user's local terminal and window manager for management. It includes a library, libshpool (v0.11.0), for creating custom wrapper binaries and supports features such as template-based variable substitution for sessions, systemd and Homebrew installation, and configurable session restore modes.

Tokens
11.6K
Snippets
26
Records
66
Agent score
83%

What's inside shpool

  1. Handle slow subscribers in the event stream

    master

    The shpool daemon uses a bounded outbound queue for each subscriber. If a subscriber falls too far behind (a "slow subscriber"), the daemon will drop the connection.

    Key behaviors to note:

    • No Replay: Events that occur while a subscriber is disconnected or being dropped are lost. There is no mechanism to catch up on missed events.
    • Reconnection: If a subscriber is dropped, it can always reconnect to the events.socket to start receiving new events from that point forward.
  2. How the shpool event stream works

    master

    shpool provides an event stream via a dedicated Unix socket, allowing external programs (like TUIs) to react to state changes without constant polling. Instead of polling, a program should listen for events on the events.socket and then call shpool list (or use the ConnectHeader::List request via the shpool-protocol crate) to refresh its local model with the current state.

    The daemon binds a sibling Unix socket next to the main socket in the <runtime_dir>/shpool/ directory:

    • <runtime_dir>/shpool/shpool.socket: The main socket for commands.
    • <runtime_dir>/shpool/events.socket: The events socket for subscribing to the event stream.

    The events socket is effectively read-only for subscribers; the daemon ignores any data written to it.

    <runtime_dir>/shpool/shpool.socket   # main socket
    <runtime_dir>/shpool/events.socket   # events socket (this protocol)
  3. Compare shpool with other session persistence tools

    master

    shpool is a session persistence tool that differs from other common tools in its philosophy and rendering model:

    vs tmux and GNU screen

    • Multiplexing vs Persistence: tmux and screen are terminal multiplexers. shpool is strictly a session persistence tool. shpool assumes terminal management (windows/panes) is the job of your display or window manager (e.g., i3, sway, xmonad).
    • Rendering: tmux renders contents remotely and sends the current view. shpool sends raw shell output directly to your local terminal. This makes shpool feel more native, as scrollback and copy-paste behave exactly like your local terminal.

    vs mosh

    • Network: mosh uses its own network protocol to handle lag. shpool is confined to a single machine and does not manage network protocols.
    • Rendering: Like tmux, mosh renders the screen remotely. shpool uses your local terminal's state machine for rendering.

    vs dtach, abduco, and diss

    • Philosophy: These tools are similar to shpool in that they eschew multiplexing and send raw bytes for local rendering.
    • Re-attachment: Unlike dtach or abduco, shpool maintains an in-memory render of the terminal state (via shpool_vt100). When you re-attach, shpool uses this to re-draw the screen, allowing you to see output that was generated while you were disconnected.
    • Prompt Context: shpool automatically injects a prefix into your prompt (for bash, zsh, or fish) to indicate the name of the shpool session.
    • Session Sharing: dtach and abduco support shared sessions. shpool only allows a single client to be connected to a particular session at a time.
  4. How shpool templates and variables work

    master

    shpool supports a template syntax for generating values based on a central list of variables. This allows you to switch multiple sessions simultaneously by changing a single variable.

    Variable Substitution

    Variables are substituted using the {var} syntax. Templates are supported in:

    • Session names
    • The attach --dir flag
    • The attach --cmd flag
    • The attach --start-cmd flag

    Switching Sessions Automatically

    When you update a variable using shpool var set <var-name> <new-value>, the shpool daemon broadcasts the new variable set to all shpool attach processes. If a session name is a template that evaluates to a different name, the shpool attach process will automatically disconnect and reconnect to the new session.

    Example:

    1. Set a variable: shpool var set workspace shpool
    2. Attach to templated sessions: shpool attach '{workspace}-edit' and shpool attach '{workspace}-main'
    3. Switch workspace: shpool var set workspace yourco
    4. The terminals will automatically switch to yourco-edit and yourco-main.
    shpool var set workspace yourco
  5. Use shpool for persistent shell sessions

    master

    The primary use case for shpool is to maintain persistent shell sessions on a remote host. shpool must be installed on the remote host, but no extra software is required on the client.

    Typical Workflow

    1. SSH into the remote host.
    2. Create or join a named session: shpool attach <session_name> (e.g., shpool attach main).
    3. If your connection drops, SSH back in and run the same command to re-attach to the existing session.

    Handling Stuck Connections

    If a terminal window is forcibly closed and shpool thinks a terminal is still connected (often due to an SSH proxy holding the connection open), you can force the session to detach by running:

    shpool detach <session_name>
    shpool attach main
  6. Configure shpool via config.toml

    master
    You can specify the path to your configuration file using the -c /path/to/config.toml flag when running shpool commands. Alternatively, you can create and edit the default configuration file located at ~/.config/shpool/config.toml.
  7. Install shpool via Homebrew (macOS)

    master

    On macOS, you can install shpool using Homebrew via the project's tap:

    brew tap shell-pool/shpool
    brew install shpool

    To ensure the shpool daemon starts automatically at login, run:

    brew services start shpool
  8. Automate shpool connections via SSH config

    master

    You can automate connecting to specific shpool sessions using your client's ~/.ssh/config file.

    Using Explicitly Named Sessions

    To map specific hostnames to shpool sessions (e.g., main and edit), add a block like this to your ~/.ssh/config:

    Host = main edit
        Hostname remote.host.example.com
    
        RemoteCommand shpool attach -f %k
        RequestTTY yes

    With this config, running ssh main or ssh edit will automatically attach to the corresponding shpool session. The %k token expands to the host name provided in the command.

    Using Local TTY for Automatic Sessions

    To generate a unique session name based on your local terminal's TTY, use this configuration:

    Host = by-tty
        User remoteuser
        Hostname remote.host.example.com
    
        RemoteCommand shpool attach -f "ssh-$(basename $(tty))"
        RequestTTY yes

    Invoking ssh by-tty will then attach to a session named after your local TTY (e.g., ssh-pts-0).

  9. Configure bash to prevent background process leaks

    master

    If you use bash, it is recommended to enable the huponexit option. This ensures that child processes exit when you leave a shell, preventing background processes from persisting in the shpool daemon's process tree and consuming memory.

    Add the following to your ~/.bashrc:

    shopt -s huponexit
  10. Measure shpool latency with sshping

    master

    To compare the latency of a raw SSH connection against a connection using shpool, use the sshping tool.

    1. Get baseline: Run sshping -H $REMOTE_HOST on your local machine.
    2. Setup shpool session: Shell into your remote host and start a session named sshping using shpool attach sshping. Inside that session, run cat > /dev/null to set up a TTY.
    3. Measure with shpool: On your local machine, run sshping with the -e flag to execute the shpool attach command:
      sshping -H -e '/path/to/shpool attach -f sshping' $REMOTE_HOST
    $ sshping -H -e '/path/to/shpool attach -f sshping' $REMOTE_HOST
  11. Install shpool from crates.io

    master

    You can install shpool using cargo.

    To run the shpool daemon via systemd, run the following commands to set up the service and socket, enable it, and ensure it runs even when no user is logged in via loginctl enable-linger:

    cargo install shpool
    curl -fLo "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/shpool.service" --create-dirs https://raw.githubusercontent.com/shell-pool/shpool/master/systemd/shpool.service
    sed -i "s|/usr|$HOME/.cargo|" "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/shpool.service"
    curl -fLo "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/shpool.socket" --create-dirs https://raw.githubusercontent.com/shell-pool/shpool/master/systemd/shpool.socket
    systemctl --user enable shpool
    systemctl --user start shpool
    loginctl enable-linger

    Without systemd

    If you do not use systemd, you can simply run:

    cargo install shpool

    shpool features autodaemonization by default, meaning it will attempt to fork a daemon process if it detects one is missing. You can control this behavior using the nodaemonize configuration option or the -d/-D command line switches.

    cargo install shpool
    curl -fLo "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/shpool.service" --create-dirs https://raw.githubusercontent.com/shell-pool/shpool/master/systemd/shpool.service
    sed -i "s|/usr|$HOME/.cargo|" "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/shpool.service"
    curl -fLo "${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user/shpool.socket" --create-dirs https://raw.githubusercontent.com/shell-pool/shpool/master/systemd/shpool.socket
    systemctl --user enable shpool
    systemctl --user start shpool
    loginctl enable-linger
  12. Install shpool as a systemd user service

    master

    You can run the shpool daemon as a user-level systemd service using the provided unit files.

    1. Install unit files: Copy the service and socket files to your user configuration directory:
      mkdir -p ~/.config/systemd/user
      cp systemd/* ~/.config/systemd/user
    2. Enable and start:
      systemctl --user enable shpool
      systemctl --user start shpool
    $ mkdir -p ~/.config/systemd/user
    $ cp systemd/* ~/.config/systemd/user
    $ systemctl --user enable shpool
    $ systemctl --user start shpool