up: The Ultimate Plumber — Build Pipelines Interactively With Live Output

2026-06-13

You know the dance. You type ps auxf | grep something, hit enter, squint, press up-arrow, add | awk '{print $2}', hit enter, squint, up-arrow, append | sort -u, repeat. Every iteration re-runs the whole pipeline, even the expensive parts. If the first command takes 30 seconds (or charges you cloud API credits), your pipeline-building feedback loop is dead before it starts.

up — the Ultimate Plumber by Mateusz Czapliński — fixes this in the most Unix way imaginable: it reads stdin once, then gives you a TUI where the pipeline you're typing is re-executed against that buffered input on every keystroke. You see the result of your evolving filter immediately, with no re-fetching, no re-running, no rate-limit anxiety.

Install from github.com/akavel/up (single Go binary, no dependencies). Then:

$ lsof | up

The top pane shows the buffered output of lsof. The bottom is an input line. Type:

grep TCP

The top pane immediately re-renders, filtered. Keep typing:

grep TCP | awk '{print $1, $9}' | sort | uniq -c | sort -rn | head

Every character updates the output. There is no execute step. When you're happy, hit Ctrl-X and up writes your pipeline to ./up1.sh as a real shell script you can commit.

The killer case is expensive or non-idempotent input:

# Hit one slow API, then iterate freely against the cached body
$ curl -s https://api.example.com/v1/everything | up

# Or a 4GB log file you don't want to re-stream
$ zcat huge.log.gz | up

# Or stdin from a remote box you SSH'd into
$ ssh prod1 'journalctl -u nginx --since "1 hour ago"' | up

One curl, one zcat, one ssh round-trip — then arbitrary pipeline iteration against the captured bytes. The mainstream alternative (shell history + arrow keys) re-runs the source command every single time you tweak a filter. Watch your AWS bill agree.

A few less-obvious moves:

Two real gotchas. First, up buffers stdin in memory by default — for genuinely huge inputs, pre-filter before piping in, or use the -b flag to bound the buffer. Second, your pipeline runs on every keystroke, so don't pipe in rm -rf; up is for read-side filters. Stick to grep/awk/sed/jq/sort/cut and friends and you cannot hurt yourself.

The deeper lesson: separating data acquisition from data shaping is one of those ideas that feels obvious once you've used it for a week, and indefensibly absent from shell ergonomics for the previous 50 years.

Key Takeaway: up buffers stdin once and re-runs your pipeline against the cached bytes on every keystroke, turning "type, enter, squint, up-arrow" into a real interactive feedback loop — then writes the final pipeline out as a reproducible shell script.

All newsletters