Posted on
Artificial Intelligence

Artificial Intelligence Prompt Libraries

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Stop Rewriting Prompts: Build a Reusable AI Prompt Library in Your Bash Workflow

If you’ve ever typed the same “You are a helpful assistant. Use bullet points. Cite sources.” three times in one day, you’ve got a problem a prompt library can fix. Treat prompts like code: version them, test them, preview them, and run them from your terminal.

This article shows you how to stand up a simple, fast, shell-first prompt library on Linux. You’ll get structure, speed, and reproducibility without leaving Bash.

Why prompt libraries matter (especially on Linux)

  • Reuse and speed: You keep your best prompts as files, not in your head or browser history.

  • Consistency: A single source of truth reduces drift across teams and projects.

  • Reproducibility: Inputs in, outputs out. Prompts become part of your pipeline and logs.

  • Collaboration: Git review, diffs, branches, and pull requests work just as well for prompts as they do for scripts.

  • Auditability: A clear trail of which prompt generated which output is invaluable for compliance and debugging.

What we’ll build

  • A simple folder structure for prompts (Markdown/text with variables).

  • A tiny Bash tool to search, fill variables, and send prompts to an OpenAI-compatible API.

  • Real-world examples you can use immediately.

  • Package-install commands for apt, dnf, and zypper.

Note: The API bits use any OpenAI-compatible endpoint (OpenAI, Azure OpenAI, local servers that speak the same API, LM Studio, etc.). You control it via env vars.


1) Scaffold your prompt library

Create a home for prompts with a few domains and variables you can fill at run time.

mkdir -p ~/prompts/{code,ops,analytics}

Example prompt: code review for Bash scripts with variable placeholders.

cat > ~/prompts/code/bash_code_review.md <<'EOF'
# Title: Bash Code Review
# Purpose: Review a Bash script for correctness, portability, and security.

You are a senior Bash engineer. Review the following script.

Requirements:

- Point out POSIX portability issues.

- Flag any unsafe patterns (word splitting, globbing, unquoted variables).

- Suggest improvements and rationale.

- ${STYLE:-brief} tone.

Script metadata:

- File: ${FILENAME}

- Context: ${CONTEXT:-general use}

Script:
----------------
${SCRIPT}
----------------
EOF

Two more examples to make it a library:

cat > ~/prompts/ops/incident_postmortem.md <<'EOF'
# Title: Incident Postmortem
You are a reliability engineer documenting an incident.

Include:

- Summary (2-3 sentences)

- Impact (numbers if available)

- Timeline (UTC)

- Root cause analysis (5 Whys)

- Corrective actions (owner & date)

- Preventive measures
Use a neutral, blameless tone. Customer-facing summary at the top.

Incident:
${INCIDENT_TEXT}
EOF
cat > ~/prompts/analytics/sql_fixer.md <<'EOF'
# Title: SQL Fixer
You are a SQL expert. Given a broken query and an error message, return a corrected query and explain the fix.

DB dialect: ${DIALECT:-PostgreSQL}
Error message: ${ERROR}
Broken query:
${QUERY}
EOF

Version-control your library:

cd ~/prompts
git init
git add .
git commit -m "seed: code review, incident postmortem, sql fixer"

2) Install terminal tooling (fzf, ripgrep, jq, curl, gettext)

We’ll use:

  • fzf for fast selection

  • ripgrep (rg) for lightning search

  • jq to parse JSON responses

  • curl for HTTP

  • gettext’s envsubst for variable substitution

  • git for version control

Install with your package manager.

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y git curl jq fzf ripgrep gettext-base
  • Fedora/RHEL/CentOS (dnf):
sudo dnf install -y git curl jq fzf ripgrep gettext
  • openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y git curl jq fzf ripgrep gettext-tools

3) A tiny Bash runner to search, fill, and send prompts

Save this as ~/bin/ai-prompt and make it executable. It:

  • Lets you pick a prompt with fzf

  • Detects variables like ${VAR}

  • Prompts for values if not set in your environment

  • Substitutes values and sends the prompt to an OpenAI-compatible API

  • Prints the model’s response

mkdir -p ~/bin
cat > ~/bin/ai-prompt <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

LIBDIR="${PROMPT_LIB:-$HOME/prompts}"
MODEL="${MODEL:-gpt-4o-mini}"
BASE_URL="${OPENAI_BASE_URL:-https://api.openai.com/v1}"
API_KEY="${OPENAI_API_KEY:-}"

need() { command -v "$1" >/dev/null 2>&1 || { echo "Missing: $1" >&2; exit 1; }; }

need fzf
need rg
need jq
need curl
need envsubst

if [[ ! -d "$LIBDIR" ]]; then
  echo "Prompt library not found at $LIBDIR" >&2
  exit 1
fi

# Pick a file
FILE="$(find "$LIBDIR" -type f \( -name '*.md' -o -name '*.txt' -o -name '*.prompt' \) | sort | fzf --prompt='Select prompt > ' --preview='sed -n "1,200p" {}' --preview-window=right:70%)"
[[ -n "${FILE:-}" ]] || { echo "No file selected."; exit 1; }

# Gather variables like ${VAR_NAME}
mapfile -t VARS < <(grep -o '\${[A-Za-z_][A-Za-z0-9_]*}' "$FILE" | tr -d '${}' | sort -u || true)

# Ask for missing values unless already in env or with default syntax ${VAR:-default}
render_tmp="$(mktemp)"
defaults_tmp="$(mktemp)"

# Extract defaults of the form ${VAR:-default text}
# We will use awk to capture var and default
awk '
  {
    while (match($0, /\$\{[A-Za-z_][A-Za-z0-9_]*:-[^}]*\}/)) {
      token=substr($0,RSTART,RLENGTH)
      gsub(/^\$\{|\}$/, "", token)
      split(token, a, ":-")
      var=a[1]; def=a[2]
      print var "\t" def
      $0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)
    }
  }
' "$FILE" | sort -u > "$defaults_tmp" || true

declare -A DEF
while IFS=$'\t' read -r k v; do
  [[ -n "$k" ]] && DEF["$k"]="$v"
done < "$defaults_tmp" || true

# Prompt user for values only if not already set
for v in "${VARS[@]}"; do
  # Skip variables that appear only as ${VAR:-default} since envsubst uses env or default
  # But if env is set, it overrides default. If not set and default exists, no need to ask.
  if [[ -z "${!v:-}" && -z "${DEF[$v]:-}" ]]; then
    read -rp "$v: " val
    export "$v=$val"
  fi
done

# Render with envsubst (handles ${VAR} and ${VAR:-default})
envsubst < "$FILE" > "$render_tmp"

echo "=== Rendered prompt ($(basename "$FILE")) ==="
sed -n '1,120p' "$render_tmp"
echo "=== Sending to model: $MODEL ===" >&2

# Require API key for OpenAI-compatible flows
if [[ -z "$API_KEY" ]]; then
  echo "OPENAI_API_KEY is not set. Export it, e.g.: export OPENAI_API_KEY=sk-..." >&2
  echo "If using a local OpenAI-compatible server without auth, set OPENAI_API_KEY=dummy and override OPENAI_BASE_URL." >&2
  exit 1
fi

resp="$(curl -sS -X POST "$BASE_URL/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<JSON
{
  "model": "$MODEL",
  "messages": [
    { "role": "user", "content": $(jq -Rs . < "$render_tmp") }
  ],
  "temperature": 0.2
}
JSON
)"

# Print model response or error
if [[ "$(echo "$resp" | jq -r '.choices[0].message.content? // empty')" != "" ]]; then
  echo
  echo "=== Model Response ==="
  echo "$resp" | jq -r '.choices[0].message.content'
else
  echo "Request failed or invalid response:" >&2
  echo "$resp" | jq .
  exit 1
fi

rm -f "$render_tmp" "$defaults_tmp"
EOF

chmod +x ~/bin/ai-prompt

Environment setup (put these in your shell profile if you like):

export OPENAI_API_KEY="sk-...your-key..."
# Optional: point to a different endpoint (LM Studio, local proxy, Azure OpenAI, etc.)
# export OPENAI_BASE_URL="http://localhost:1234/v1"
# export MODEL="gpt-4o-mini"
# export PROMPT_LIB="$HOME/prompts"

Run it:

ai-prompt

Pick a prompt, fill any variables, get the result.

Tip: If a variable has a default like ${STYLE:-brief}, you won’t be asked for it unless you export STYLE to override.


4) Real-world examples

  • Code review a Bash script
export FILENAME="backup.sh"
export CONTEXT="Runs nightly via cron"
export STYLE="thorough"
export SCRIPT="$(sed -n '1,200p' ./backup.sh)"
ai-prompt
  • Draft an incident postmortem
export INCIDENT_TEXT="$(cat incident_notes.txt)"
ai-prompt
  • Fix a SQL query by dialect
export DIALECT="PostgreSQL"
export ERROR="ERROR: syntax error at or near 'fromm' LINE 1: select * fromm users"
export QUERY="select * fromm users where created_at > now() - interval '7 days';"
ai-prompt

Pro tip: Pre-export commonly used variables in task-specific shell aliases or tiny wrapper scripts for repeatability.


5) Treat prompts like code: search, test, and version

  • Fast search across your library:
rg -n "postmortem|review" ~/prompts
  • Branch, review, and tag:
cd ~/prompts
git checkout -b feature/tighter-bash-review
$EDITOR code/bash_code_review.md
git commit -am "bash review: add word-splitting check; default tone=brief"
git tag -a v0.2 -m "Improve Bash review template"
  • Simple A/B checks (two prompt variants on the same input):
cat > ~/bin/prompt-ab <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
A="$1"; B="$2"; shift 2
export SCRIPT="$(cat "$1")"
export FILENAME="${2:-sample.sh}"
echo "== A: $(basename "$A") =="
PROMPT_LIB="$(dirname "$A")" MODEL="${MODEL:-gpt-4o-mini}" OPENAI_API_KEY="${OPENAI_API_KEY:?}" \
  OPENAI_BASE_URL="${OPENAI_BASE_URL:-https://api.openai.com/v1}" ai-prompt <<< "$A" || true
echo
echo "== B: $(basename "$B") =="
PROMPT_LIB="$(dirname "$B")" MODEL="${MODEL:-gpt-4o-mini}" OPENAI_API_KEY="${OPENAI_API_KEY:?}" \
  OPENAI_BASE_URL="${OPENAI_BASE_URL:-https://api.openai.com/v1}" ai-prompt <<< "$B" || true
EOF
chmod +x ~/bin/prompt-ab

Usage:

prompt-ab ~/prompts/code/bash_code_review.md ~/prompts/code/bash_code_review_alt.md ./backup.sh

You can redirect outputs to files and diff them to see which prompt works better for your use case.

Security note: Never paste secrets into prompts. Keep secrets out of your prompt files and inputs. Consider scanning your repo with your existing secret detectors before pushing.


Troubleshooting

  • fzf not found: Ensure you installed it with your package manager and that ~/bin is on your PATH.

  • API issues: Verify OPENAI_API_KEY, OPENAI_BASE_URL, and MODEL are correct. Some OpenAI-compatible servers use different model names; set MODEL accordingly.

  • Variable not replaced: Ensure you used ${VAR} or ${VAR:-default} syntax in the prompt template.


Conclusion and next steps

You now have:

  • A structured prompt library in ~/prompts

  • A tiny Bash tool to pick, fill, and run prompts from the terminal

  • Real examples you can adapt to your workflow

Next steps:

  • Add your own domain-specific prompts (security reviews, SRE runbooks, migration guides).

  • Share your library via Git and code review your prompts like any other artifact.

  • Bake the tool into scripts, pre-commit hooks, or CI to make high-quality outputs repeatable.

Stop reinventing prompts. Start shipping them.