Posted on
Artificial Intelligence

Artificial Intelligence Ollama Projects

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

4 Practical Ollama Projects You Can Build with Pure Bash on Linux

If you’ve ever wished you could use powerful AI models directly from your terminal—without sending your data to the cloud—this is your moment. Ollama makes it easy to run large language models (LLMs) locally, and with a few Bash scripts you can automate real work: generate commit messages, summarize logs, or query your docs with a tiny RAG pipeline.

This post shows why running AI locally is worth your time, then walks you through four hands-on Ollama projects you can build today—entirely from Bash.

Why Ollama on Linux?

  • Privacy by default: Your prompts and data never leave your machine.

  • Cost control: No per-token API bills. Run as much as you want on your hardware.

  • Low latency: Local inference is fast for most 7B/8B models, and even faster with a GPU.

  • Unix-native workflow: Pipe, filter, and compose with standard tools (bash, jq, ripgrep, systemd, cron).

Prerequisites

We’ll install a few common CLI tools. Choose the commands for your distro.

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

Install Ollama

The recommended Linux install is a one-liner script that sets up the ollama binary and a systemd service.

curl -fsSL https://ollama.com/install.sh | sh

Start and enable the service (system-wide):

sudo systemctl enable --now ollama
sudo systemctl status ollama

If your environment prefers a user service:

systemctl --user enable --now ollama
systemctl --user status ollama

Verify:

ollama --version
ollama list

Optional: run via Docker instead of systemd:

docker run -d --name ollama -p 11434:11434 -v ollama:/root/.ollama ollama/ollama

Pull a few models we’ll use:

ollama pull llama3
ollama pull codellama
ollama pull nomic-embed-text

Notes:

  • llama3 is a strong general-purpose instruction model.

  • codellama works well for code-oriented prompts.

  • nomic-embed-text generates embeddings for similarity search (for our mini-RAG).


Project 1: A one-liner terminal assistant

Use a local LLM like a shell tool. Great for quick explanations or throwaway drafts.

  • Interactive:
ollama run llama3
  • One-off output you can pipe or capture:
ollama generate -m llama3 -p "Explain the difference between hard links and symbolic links in Linux. Keep it under 120 words."
  • With a lightweight “system prompt”:
SYS="You are a concise Linux assistant. Prefer examples and POSIX tools."
Q="Show a one-liner to find the 10 largest files under /var, excluding /var/log."
ollama generate -m llama3 -p "$SYS"$'\n\n'"Question: $Q"

Actionable tip: For automation, always prefer ollama generate (non-interactive) over ollama run (REPL).


Project 2: AI-assisted Git commit messages (conventional commits)

Turn your staged diff into a well-structured commit message.

Create a script git-commit-ai somewhere on your PATH:

#!/usr/bin/env bash
set -euo pipefail

MODEL="${MODEL:-llama3}"

# Make sure there are staged changes.
if ! git diff --cached --quiet; then
  :
else
  echo "No staged changes. Stage some files first (e.g., `git add -p`)."
  exit 1
fi

DIFF="$(git diff --cached)"
PROMPT="$(cat <<'EOF'
You are an expert at writing conventional commit messages.

Rules:

- Use a present-tense, imperative subject line (<= 72 chars).

- Use a conventional type like: feat, fix, docs, style, refactor, perf, test, chore.

- Provide a detailed body with bullet points when useful.

- Mention breaking changes under "BREAKING CHANGE:" if applicable.

- Infer scope (e.g., cli, api, docs) when obvious.

Generate only the commit message.
EOF
)"

MSG="$(ollama generate -m "$MODEL" -p "$PROMPT"$'\n\n'"Diff:\n$DIFF")"

# Let the user review in the standard editor:
printf '%s\n' "$MSG" > .git/COMMIT_EDITMSG
git commit -e -F .git/COMMIT_EDITMSG

Make it executable:

chmod +x git-commit-ai

Use it:

git add -p
git-commit-ai

Tip: For code-heavy repos, try MODEL=codellama git-commit-ai.


Project 3: Mini RAG in pure Bash + jq (Ask your local docs)

This simple retrieval-augmented generation (RAG) setup indexes your .md and .txt files, finds the most relevant chunks using embeddings, and feeds them to a model for grounded answers.

We’ll create two scripts: one to build an index, and one to ask questions.

1) Index your docs into index.jsonl:

#!/usr/bin/env bash
# index.sh: build a tiny embedding index from docs/*.md, *.txt
set -euo pipefail

DOC_DIR="${1:-docs}"
MODEL_EMB="${MODEL_EMB:-nomic-embed-text}"
INDEX="${2:-index.jsonl}"

[ -d "$DOC_DIR" ] || { echo "No $DOC_DIR directory"; exit 1; }
: > "$INDEX"

# Function: JSON-escape stdin to a string
json_escape() { jq -Rs '.'; }

# Chunking: ~1500 characters per chunk (rough but effective)
chunk_file() {
  local file="$1"
  awk -v max=1500 -v file="$file" '
    BEGIN { buf=""; }
    {
      if (length(buf) + length($0) + 1 > max) {
        print buf;
        buf="";
      }
      buf = (buf=="" ? $0 : buf ORS $0);
    }
    END {
      if (length(buf)>0) print buf;
    }
  ' "$file"
}

embed() {
  local text="$1"
  curl -sS http://localhost:11434/api/embeddings \
    -d "{\"model\":\"$MODEL_EMB\",\"prompt\":$text}" \
  | jq -c '.embedding'
}

id=0
shopt -s nullglob
for f in "$DOC_DIR"/*.md "$DOC_DIR"/*.txt; do
  while IFS= read -r chunk; do
    esc="$(printf '%s' "$chunk" | json_escape)"
    emb="$(embed "$esc")"
    printf '{"id":%s,"source":%s,"text":%s,"embedding":%s}\n' \
      "$id" "$(printf '%s' "$f" | jq -R '.')" "$esc" "$emb" >> "$INDEX"
    id=$((id+1))
  done < <(chunk_file "$f")
done

echo "Indexed $id chunks into $INDEX"

2) Ask a question using the index:

#!/usr/bin/env bash
# ask.sh: query the index with a question; returns grounded answer
set -euo pipefail

INDEX="${1:-index.jsonl}"
QUESTION="${2:-}"
MODEL_GEN="${MODEL_GEN:-llama3}"
MODEL_EMB="${MODEL_EMB:-nomic-embed-text}"

[ -s "$INDEX" ] || { echo "Missing or empty $INDEX. Run ./index.sh first."; exit 1; }
[ -n "$QUESTION" ] || { echo "Usage: ./ask.sh index.jsonl 'Your question'"; exit 1; }

# 1) Embed the question
QEMB="$(curl -sS http://localhost:11434/api/embeddings \
  -d "{\"model\":\"$MODEL_EMB\",\"prompt\":$(printf '%s' "$QUESTION" | jq -Rs '.')}" \
  | jq -c '.embedding')"

# 2) Rank chunks by cosine similarity (jq 1.6+)
TOPK_JSON="$(jq -s --argjson q "$QEMB" '
  def dot(a;b): reduce range(0; a|length) as $i (0; . + (a[$i]*b[$i]));
  def norm(a): (reduce a[] as $x (0; . + ($x*$x))) | sqrt;
  def cosine(a;b): (dot(a;b)) / ((norm(a) * norm(b)) + 1e-9);
  map(. + {score: cosine(.embedding; $q)}) | sort_by(-.score) | .[:3]
' "$INDEX")"

# 3) Build context string from the top chunks
CONTEXT="$(printf '%s' "$TOPK_JSON" | jq -r '.[] | "From: \(.source)\n---\n\(.text)\n"' )"

# 4) Ask the generator model with the retrieved context
PROMPT="$(cat <<EOF
You are a precise assistant. Use ONLY the provided context to answer.
If the answer is not in the context, say you don't know.

Context:
$CONTEXT

Question: $QUESTION
Answer:
EOF
)"
ollama generate -m "$MODEL_GEN" -p "$PROMPT"

Usage:

mkdir -p docs
cp README.md docs/
./index.sh docs index.jsonl
./ask.sh index.jsonl "How do I run the CLI tool? Provide exact flags if present."

Notes:

  • Adjust chunk size or K (top 3) as needed.

  • For larger corpora, consider storing index.jsonl somewhere persistent and automating index.sh with cron.


Project 4: Summarize system logs (cron-friendly)

Get a clean summary of your last hour of service logs—perfect for on-call or daily reports.

One-shot summary:

SERVICE="nginx"
LOGS="$(journalctl -u "$SERVICE" --since '1 hour ago' -o short-iso | tail -n 2000)"
PROMPT="Summarize the following $SERVICE logs from the last hour. Identify errors, recurring issues, and suggested next steps. Be concise."

ollama generate -m llama3 -p "$PROMPT"$'\n\n'"Logs:\n$LOGS"

Automate with cron to send a summary to a file every hour:

crontab -e

Add:

0 * * * * SERVICE=nginx /bin/bash -lc 'LOGS="$(journalctl -u "$SERVICE" --since "1 hour ago" -o short-iso | tail -n 2000)"; PROMPT="Summarize the following $SERVICE logs from the last hour. Identify errors, recurring issues, and suggested next steps."; ollama generate -m llama3 -p "$PROMPT"$'\n\n'"Logs:\n$LOGS" > "$HOME/${SERVICE}_summary_$(date +\%Y-\%m-\%d_\%H00).txt"'

Tip: Pipe very noisy logs through grep -v or sed to remove control characters and keep prompts under a few tens of thousands of characters.


Troubleshooting and tips

  • GPU acceleration: If you have a supported GPU and drivers, Ollama will try to use it automatically; check ollama show llama3 for details and nvidia-smi for load.

  • Service health: sudo systemctl status ollama (or systemctl --user status ollama) to verify it’s running on port 11434.

  • Model sizes: Prefer 7B/8B models for laptops; larger models need more RAM/VRAM.

  • Light dependencies recap:

    • Debian/Ubuntu: sudo apt install -y curl jq git ripgrep
    • Fedora/RHEL/CentOS: sudo dnf install -y curl jq git ripgrep
    • openSUSE: sudo zypper --non-interactive install curl jq git ripgrep

Conclusion and next steps

You’ve just built four useful, privacy-preserving AI workflows entirely in Bash:

  • Quick terminal assistant

  • AI commit messages

  • A tiny but real RAG for your docs

  • Log summarization on a schedule

From here, you can:

  • Swap models (ollama pull mistral, ollama pull qwen2) to see what works best.

  • Add caching to the RAG index.

  • Wrap your scripts with fzf for a TUI, or expose them via a tiny HTTP server.

Call to action:

  • Install Ollama and run your first one-liner today:
curl -fsSL https://ollama.com/install.sh | sh
sudo systemctl enable --now ollama
ollama pull llama3
ollama generate -m llama3 -p "What should I automate with Bash and a local LLM?"

Your terminal just got a whole lot smarter—without leaving your machine.