- Posted on
- • Artificial Intelligence
Reusable Prompt Workflows
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Reusable Prompt Workflows: Turn One-Off Commands Into Reliable, Repeatable CLI Flows
Ever copy a complex command from shell history and pray you don’t forget a critical flag? Or DM a teammate the “magic incantation” for deploying to staging—only to fix a typo later? Reusable prompt workflows turn those fragile, one-off CLI moments into guided, repeatable flows you can trust and share.
In this article, we’ll build small, interactive Bash tools that:
Ask for just the parameters that change
Enforce safe defaults and guardrails
Work consistently across machines and distros
Save time and reduce mistakes
We’ll use plain Bash plus widely available tools like fzf, dialog, and jq. Installation instructions are included for apt, dnf, and zypper.
Why reusable prompt workflows?
Reduce cognitive load: You don’t have to remember long flag sets or exact paths.
Fewer production mistakes: Confirmations and previews catch dangerous actions.
Faster onboarding: New teammates can run reliable scripts instead of memorizing commands.
Shareability: Put workflows under version control; evolve them as your stack changes.
Install the tools we’ll use
All examples run with standard Bash. For enhanced selection and menus, install these packages:
fzf: Fuzzy finder for interactive lists
dialog (or whiptail): Simple TUI dialog boxes
jq: JSON parsing to make data-driven choices
git and rsync: Used by example scripts
Ubuntu/Debian (apt):
sudo apt update
sudo apt install -y fzf dialog jq git rsync
# Optional alternative to dialog:
sudo apt install -y whiptail
Fedora/RHEL/CentOS (dnf):
sudo dnf install -y fzf dialog jq git rsync
# Optional alternative to dialog (whiptail comes from 'newt'):
sudo dnf install -y newt
openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y fzf dialog jq git rsync
# Optional alternative to dialog:
sudo zypper install -y newt
Tip: Put your own scripts in ~/bin and add it to PATH:
mkdir -p "$HOME/bin"
echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc"
source "$HOME/.bashrc"
1) Start small: wrap a risky or verbose command
Take something you do often—like syncing a folder, rotating logs, or creating a backup. Wrap it with prompts and sane defaults so you can’t “fat-finger” it.
Example: A safe, parameterized backup with confirmation and dry-run.
Save as ~/bin/backup-it and make executable (chmod +x ~/bin/backup-it):
#!/usr/bin/env bash
set -euo pipefail
usage() {
echo "Usage: $0 [-s source_dir] [-d dest_dir] [-c compression] [-n]"
echo " -s Source directory (default: current directory)"
echo " -d Destination directory (default: ~/backups)"
echo " -c Compression: gz|xz|zst (default: gz)"
echo " -n Dry-run (no changes)"
}
SRC="${PWD}"
DEST="$HOME/backups"
COMP="gz"
DRY_RUN=0
while getopts ":s:d:c:n" opt; do
case "$opt" in
s) SRC="$OPTARG" ;;
d) DEST="$OPTARG" ;;
c) COMP="$OPTARG" ;;
n) DRY_RUN=1 ;;
*) usage; exit 1 ;;
esac
done
timestamp=$(date +%Y%m%d-%H%M%S)
mkdir -p "$DEST"
case "$COMP" in
gz) TARFLAGS="czf" ; EXT="tar.gz" ;;
xz) TARFLAGS="cJf" ; EXT="tar.xz" ;;
zst) TARFLAGS="c --zstd -f" ; EXT="tar.zst" ;;
*) echo "Unsupported compression: $COMP"; exit 1 ;;
esac
ARCHIVE="$DEST/backup-$(basename "$SRC")-$timestamp.$EXT"
echo "About to create: $ARCHIVE"
echo "From source: $SRC"
echo "Compression: $COMP"
read -rp "Proceed? [y/N] " ans
[[ "${ans:-N}" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
if [[ $DRY_RUN -eq 1 ]]; then
echo "Dry-run: would run -> tar $TARFLAGS \"$ARCHIVE\" -C \"$(dirname "$SRC")\" \"$(basename "$SRC")\""
exit 0
fi
tar $TARFLAGS "$ARCHIVE" -C "$(dirname "$SRC")" "$(basename "$SRC")"
echo "Done: $ARCHIVE"
Why this helps:
Guided inputs beat guessing flags.
Confirmation avoids accidental writes.
Dry-run gives a safe preview.
2) Add speed with fuzzy selection (fzf)
Menus beat memory. Pipe lists to fzf to pick branches, containers, files, or contexts quickly.
Example: Checkout a Git branch interactively with preview. Save as ~/bin/git-pick-branch (chmod +x):
#!/usr/bin/env bash
set -euo pipefail
# Ensure we're in a git repo
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "Not a git repo"; exit 1; }
branch=$(git for-each-ref --format='%(refname:short)|%(committerdate:relative)|%(subject)' refs/heads \
| sort -r \
| fzf --with-nth=1,2,3 --delimiter='|' --preview 'git log --oneline -n 20 {1}' --height=40% --reverse \
| cut -d'|' -f1)
[[ -n "${branch:-}" ]] || { echo "No branch chosen."; exit 1; }
echo "Checking out: $branch"
git checkout "$branch"
Other quick wins for fzf:
Pick a Docker container to exec into: docker ps --format '{{.Names}}' | fzf
Pick a Kube context: kubectl config get-contexts -o name | fzf
3) Use dialog for guided, guardrailed choices
For more structured flows, dialog (or whiptail) gives you TUI menus and confirmations without complex UIs.
Example: Choose an environment and run a command. Save as ~/bin/run-in-env (chmod +x):
#!/usr/bin/env bash
set -euo pipefail
# Requires: dialog
tmp=$(mktemp)
trap 'rm -f "$tmp"' EXIT
dialog --clear --no-tags --menu "Select environment" 12 50 5 \
dev "Local development" \
stage "Staging" \
prod "Production (careful!)" 2>"$tmp"
choice=$(<"$tmp") || true
clear
[[ -n "${choice:-}" ]] || { echo "No environment chosen."; exit 1; }
echo "You chose: $choice"
case "$choice" in
dev) cmd="docker compose up --build" ;;
stage) cmd="kubectl --context stage apply -f k8s/" ;;
prod) cmd="kubectl --context prod apply -f k8s/" ;;
esac
read -rp "Run '$cmd'? [y/N] " ans
[[ "${ans:-N}" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; }
eval "$cmd"
Why this helps:
Intentional friction for prod actions
Clear, readable choices
Easy to extend with more steps
4) Make data-driven prompts with jq
Combine APIs or config files with fuzzy selection. Let data insist on the right value.
Example: Pick a service from JSON, then tail its logs. Save as services.json in your project:
[
{"name": "api", "log": "/var/log/myapp/api.log"},
{"name": "worker", "log": "/var/log/myapp/worker.log"},
{"name": "web", "log": "/var/log/myapp/web.log"}
]
Script ~/bin/tail-service (chmod +x):
#!/usr/bin/env bash
set -euo pipefail
FILE="${1:-services.json}"
[[ -f "$FILE" ]] || { echo "Missing $FILE"; exit 1; }
choice=$(jq -r '.[].name' "$FILE" | fzf --prompt="Service> ")
[[ -n "${choice:-}" ]] || { echo "No service chosen."; exit 1; }
log_path=$(jq -r ".[] | select(.name==\"$choice\").log" "$FILE")
[[ -n "$log_path" && -f "$log_path" ]] || { echo "Log not found for $choice"; exit 1; }
echo "Tailing: $choice -> $log_path"
exec tail -n 50 -f "$log_path"
Why this helps:
The source of truth is a file or API, not tribal knowledge
Avoids typos in names/paths
Easy to audit and version
5) Make it truly reusable: functions, aliases, and version control
Break down flows into small functions and source them in ~/.bashrc or a dedicated ~/.bash_libs/prompt-workflows.sh.
Add lightweight shims in ~/bin that call those functions or scripts.
Use clear names: git-pick-branch, run-in-env, tail-service, backup-it.
Commit them to a dotfiles repo so your whole team can improve them.
Example: Sourcing a shared library
# ~/.bashrc
if [[ -f "$HOME/.bash_libs/prompt-workflows.sh" ]]; then
source "$HOME/.bash_libs/prompt-workflows.sh"
fi
Real-world ideas you can ship this week
Safe cleanup: Interactively choose old log files with fzf, preview with head, confirm delete.
Release helper: Pick next semver (patch/minor/major), generate changelog from git log, tag and push.
Kubernetes doctor: Choose context/namespace, run a battery of kubectl get/describe checks, save to a timestamped report.
Branch surgeon: Pick branches merged into main and older than N days, confirm, then delete in bulk.
Wrap-up and Call to Action
Reusable prompt workflows let you encode best practices right where you work—the shell. Start with one painful or risky task:
Turn it into a script with prompts and safe defaults
Add fzf for quick selection
Use dialog for guardrails on high-stakes actions
Feed it real data with jq
Then share it. Put your scripts in ~/bin, commit them to a repo, and help your team move faster with fewer mistakes.
Your next step: pick one of the examples above and adapt it to your workflow today. When you’ve got it running, add a second one. In a week you’ll wonder how you lived without them.