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.