Introduction

Over the past year I have dedicated countless hours to building a unified terminal workflow that meshes tmux and reptyr with a parade of TUI libraries from rich / textual and PyTermGUI to curses. Why? Because while the command line is power, it is also a wall. The wall keeps potentially brilliant minds—who could advance open-source—on the wrong side of the divide. Wouldn’t it be a wonderful thing if it was possible to harness all the talent which exists on the other side? To be able to make things usable without neutering the depth power-users expect?


Discovery

On 14 Jan 2025 I disclosed a Broken Access Control flaw to Ultimate-Guitar. To automate exploitation I wrote EchoHeist – a shell script following the Regex → Replay → Redirect mantra. That project introduced me to fzf, the focal point of this article. You can read about the exploit here

echoHEIST UI
EchoHeist – dynamic target selection via fzf

Ultimately I decided not to release EchoHeist publicly—too easy to abuse—so I filed a full disclosure report instead. Yet the experience lit a beacon: fzf was the missing interface glue for many of my scripts.


tmux – the Terminal Multiplexer

tmux logo
tmux logo

tmux drew me down a rabbit-hole of panes, windows and sessions. Programmatically, though, its dynamic index renumbering is maddening:

  • pane indices shift every time you create or destroy one
  • the same problem applies to windows and even sessions
  • the only stable identifier is the pane title you assign manually

Experienced tmux hackers may shrug, but if you are writing automation the pain is real. I often fall back to raw shell ‘send-keys’ calls instead of libtmux.

A quick demonstration

The bash helper below spawns a pain_demo session, splits into four panes, shows their indices, kills one pane, adds a new pane, and lets you watch how indices reshuffle.

#!/usr/bin/env bash
# DtRH.net-pain_demo.sh  – visualise tmux index chaos

SESSION="pain_demo"

tmux has-session -t "$SESSION" 2>/dev/null
if [[ $? -ne 0 ]]; then
  echo "Creating new tmux session: $SESSION"
  tmux new-session -d -s "$SESSION" -n pain_demo

  send_cmd () { tmux send-keys -t "$SESSION:pain_demo.$1" "$2" C-m; }

  # build 4-pane grid
  tmux split-window -h -t "$SESSION:pain_demo.0"
  tmux split-window -v -t "$SESSION:pain_demo.0"
  tmux split-window -v -t "$SESSION:pain_demo.1"

  for i in 0 1 2 3; do send_cmd $i "echo 'Initial Pane Index: $i'; bash"; done
  sleep 10

  echo "Removing pane 1…"
  tmux kill-pane -t "$SESSION:pain_demo.1"
  send_cmd 0 "clear; echo 'Updated Pane Index: 0'; bash"
  send_cmd 2 "clear; echo 'Updated Pane Index: 1'; bash"
  send_cmd 3 "clear; echo 'Updated Pane Index: 2'; bash"
  sleep 10

  echo "Adding a horizontal split from pane 0…"
  tmux split-window -h -t "$SESSION:pain_demo.0"
  # panes will be renumbered 0-3 automatically
  for id in 0 1 2 3; do send_cmd $id "clear; echo 'Pane Index: $id'; bash"; done
  sleep 10
fi

tmux attach -t "$SESSION"

What about reptyr?

reptyr re-parents an existing process to your current terminal—priceless when an SSH link might drop. The classic pattern:

  1. Start a long-running job over SSH by accident.
  2. Launch tmux, use reptyr to grab the process into a pane.
  3. Disconnect safely; the process keeps running inside tmux.
  4. Reattach later.

screen can play the same role on systems lacking tmux.


FZF – Fuzzy Finder

fzf filters massive lists at lightning speed, sparing beginners from complex regular expressions.

Simple safety wrapper:

ls -l Downloads/ | grep -i '.png' | fzf -m | xargs rm
fzf file removal demo
Interactive file removal – choose files before 'rm' executes

Advanced fzf Implementations

1 · Continuous Log Viewer

Split tmux horizontally: top pane lists /var/log plus a live dmesg option via fzf; bottom pane tails the chosen log. Run until you ‘Ctrl-C’.

logview demo
Live log navigation with fzf + tmux

Source: logview.py

2 · PSHijack

Browse running processes, preview details, then (optionally) steal the TTY with reptyr.

process explorer
Process explorer + hijacker

Source: PSHijack.sh

3 · URLSex

Enter any URL, scrape every ‘href’, sort by extension, fuzzy-filter, then act on the selection.

urlsex demo
Interactive link harvesting

Source: urlsex.py


Download Table

File Language Integrations Description
logview.py Python tmux, fzf System log & event viewer
PSHijack.sh Shell tmux, reptyr, fzf Dynamic process explorer / hijacker
urlsex.py Python fzf Scrape links from a URL and act on selection

References & Resources

Tool Website
Fuzzy Finder https://github.com/junegunn/fzf
tmux https://github.com/tmux/tmux
reptyr https://github.com/nelhage/reptyr
rich (Textualize) https://github.com/Textualize/rich
curses HOWTO https://docs.python.org/3/howto/curses.html

Recents Post

Share

08

Vibe Coding with LLM Agents Friday, 6PM
PUBLIC SERVICE ANNOUNCEMENTI’m not a (total) doomster. But I’m very much well informed. And if I ...

27

Tuesday, 1AM
Context Wrangler 🚦Automated context-length hygiene • Multi-model AI prompt generator • Git-to-Ro...

Powered by Hexo