- Posted on
- • Artificial Intelligence
Creating Offline Artificial Intelligence Automation on Linux
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Creating Offline Artificial Intelligence Automation on Linux
Want private, fast, and reliable AI that doesn’t phone home? You can run modern language and speech models entirely on your Linux box and wire them into Bash for real, hands-free automation—no cloud, no API bills, and no internet required.
In this guide, you’ll set up an offline LLM and offline speech-to-text, then glue them together with Bash to build practical automations. You’ll also see how to schedule and harden them for daily use.
Why offline AI on Linux?
Privacy and control: Keep your code, logs, and voice data local.
Reliability and speed: No API latency or outage risk; inference runs at LAN speeds.
Cost: One-time setup beats usage-based billing.
Maturity: Tools like Ollama, llama.cpp, and whisper.cpp are battle-tested and easy to script.
What you’ll build:
A local LLM that can analyze text and suggest shell commands.
An offline speech-to-text pipeline to talk to your machine.
A Bash automation script that transcribes a request, asks the LLM for a safe command, and optionally runs it.
A systemd timer or cron job to schedule AI-powered maintenance checks.
1) Prepare your system
We’ll install common build tools and CLI helpers used throughout.
Apt (Debian/Ubuntu):
sudo apt update
sudo apt install -y git build-essential cmake curl wget python3 python3-venv sox alsa-utils jq make
DNF (Fedora/RHEL/CentOS Stream):
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y git cmake curl wget python3 python3-venv sox alsa-utils jq make
Zypper (openSUSE Leap/Tumbleweed):
sudo zypper refresh
sudo zypper install -y git gcc gcc-c++ cmake curl wget python3 python3-venv sox alsa-utils jq make
Notes:
alsa-utilsprovidesarecordfor simple microphone capture.jqis used to parse and validate JSON from the LLM.If you plan to use GPU acceleration later, also install your vendor’s CUDA/ROCm/OpenCL stack.
2) Install a fully local LLM
You have two popular options. Ollama is easiest; llama.cpp offers fine-grained control and tiny footprints.
Option A: Ollama (recommended for simplicity)
Ollama manages models and runs a local HTTP API at port 11434.
Install:
curl -fsSL https://ollama.com/install.sh | sh
Start the service:
sudo systemctl enable --now ollama
Pull a small, capable model (fits on most laptops):
ollama pull llama3.2:3b
Test it:
ollama run llama3.2:3b "Explain bash here-strings in two sentences."
If you see a coherent response, your local LLM is ready.
Option B: llama.cpp (build from source, minimal footprint)
Build:
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make -j
Get a GGUF model (ensure you respect licenses; place file locally):
mkdir -p ~/models
# Put your *.gguf model in ~/models, e.g. llama-3.2-3b-instruct.Q4_K_M.gguf
Run the HTTP server:
./server -m ~/models/llama-3.2-3b-instruct.Q4_K_M.gguf --port 8080
The server exposes endpoints like /completion and /chat. You can curl them similarly to Ollama (payload shape differs; see repo docs).
3) Add offline speech-to-text with whisper.cpp
We’ll compile whisper.cpp and use arecord to capture 16 kHz mono WAV (no external libraries required).
Build whisper.cpp:
git clone https://github.com/ggerganov/whisper.cpp
cd whisper.cpp
make -j
Download an English model (base.en is small and accurate enough for commands):
cd whisper.cpp
bash ./models/download-ggml-model.sh base.en
Record and transcribe a test:
# Record 5 seconds of audio from default ALSA device
arecord -f S16_LE -r 16000 -c 1 /tmp/clip.wav -d 5
# Transcribe
./main -m models/ggml-base.en.bin -f /tmp/clip.wav -of /tmp/transcript.txt
# Show result
cat /tmp/transcript.txt
If you get readable text, you’re ready to wire voice into your offline assistant.
4) Wire it together with Bash: voice → LLM → safe command execution
This example:
Records your voice,
Transcribes it locally with whisper.cpp,
Asks your local LLM (Ollama) to propose a safe shell command in strict JSON,
Asks for confirmation, then executes it.
Create ~/bin/offline_voice_agent.sh:
#!/usr/bin/env bash
set -euo pipefail
# Config
DURATION="${DURATION:-6}" # seconds to record
AUDIO="/tmp/voice_cmd.wav"
TRANSCRIPT="/tmp/voice_cmd.txt"
WHISPER_DIR="${WHISPER_DIR:-$HOME/whisper.cpp}"
WHISPER_MODEL="${WHISPER_MODEL:-$WHISPER_DIR/models/ggml-base.en.bin}"
OLLAMA_MODEL="${OLLAMA_MODEL:-llama3.2:3b}"
DRY_RUN="${DRY_RUN:-true}" # set to "false" to allow execution
ALLOWLIST="${ALLOWLIST:-apt|dnf|zypper|ls|cat|tail|head|du|df|free|journalctl|systemctl|nmcli|ip|ping}"
# Ensure deps
command -v arecord >/dev/null || { echo "arecord (alsa-utils) is required"; exit 1; }
test -x "$WHISPER_DIR/main" || { echo "Build whisper.cpp and set WHISPER_DIR"; exit 1; }
command -v jq >/dev/null || { echo "jq is required"; exit 1; }
command -v ollama >/dev/null || { echo "ollama is required"; exit 1; }
echo "[1/4] Recording ${DURATION}s of audio..."
arecord -f S16_LE -r 16000 -c 1 "$AUDIO" -d "$DURATION"
echo "[2/4] Transcribing speech (whisper.cpp)..."
"$WHISPER_DIR/main" -m "$WHISPER_MODEL" -f "$AUDIO" -of "$TRANSCRIPT" >/dev/null
QUERY="$(tr -d '\0' < "$TRANSCRIPT" | tr '\n' ' ' | sed 's/ */ /g')"
echo "You said: $QUERY"
# System prompt to enforce STRICT JSON
read -r -d '' SYS <<'EOF'
You are an offline Linux command assistant. Return ONLY JSON:
{"command": "...", "reason": "..."}
- command: a single safe shell command that addresses the user's request using common tools (bash coreutils, package managers, systemctl, journalctl, ip, df, du, free).
- Prefer read-only commands unless explicitly asked to make changes.
- NEVER include explanations outside JSON. No backticks. No multiple commands joined with && or ;.
- Use the user's distro package manager only if asked to install.
- Assume no internet.
EOF
echo "[3/4] Asking local LLM ($OLLAMA_MODEL) for a command..."
RESP="$(curl -s http://localhost:11434/api/generate -d @- <<JSON
{
"model": "$OLLAMA_MODEL",
"prompt": "$SYS\nUser: $QUERY\nAssistant:",
"options": { "temperature": 0.1 },
"stream": false
}
JSON
)"
# Extract the model's text field
TEXT="$(echo "$RESP" | jq -r '.response')"
# Validate strict JSON and parse command
if ! echo "$TEXT" | jq -e . >/dev/null 2>&1; then
echo "Model did not return valid JSON. Raw output:"
echo "$TEXT"
exit 1
fi
CMD="$(echo "$TEXT" | jq -r '.command')"
REASON="$(echo "$TEXT" | jq -r '.reason')"
if [[ -z "$CMD" || "$CMD" == "null" ]]; then
echo "No command proposed. Full payload:"
echo "$TEXT"
exit 1
fi
# Basic allowlist
if ! [[ "$CMD" =~ ^($ALLOWLIST)\b ]]; then
echo "Proposed command not in allowlist: $CMD"
echo "Reason: $REASON"
exit 1
fi
echo "[4/4] Proposed command:"
echo " $CMD"
echo "Reason: $REASON"
read -rp "Execute? [y/N] " ans
if [[ "$ans" =~ ^[Yy]$ && "$DRY_RUN" != "true" ]]; then
bash -lc "$CMD"
else
echo "Dry-run or not confirmed. Skipping execution."
fi
Make it executable:
chmod +x ~/bin/offline_voice_agent.sh
Run it:
~/bin/offline_voice_agent.sh
Try prompts like:
“How full is my disk?” →
df -h“Show the last 50 kernel log lines” →
journalctl -k -n 50“Check current memory usage” →
free -h
Hygiene and safety tips:
Keep
DRY_RUN=truewhile testing.Tighten
ALLOWLISTto the smallest set you actually need.Consider a review step that prints the command, diffs expected changes, or runs inside a container/namespace.
5) Schedule and operationalize
You can run AI automations on a schedule (health checks, log summaries) entirely offline.
Example: a daily log summary using your local LLM.
Create ~/bin/offline_log_summary.sh:
#!/usr/bin/env bash
set -euo pipefail
MODEL="${MODEL:-llama3.2:3b}"
# Collect recent logs (adjust scope and amount)
journalctl -p 4 -n 500 --no-pager > /tmp/journal_excerpt.txt
read -r -d '' PROMPT <<'EOF'
Summarize the key issues, repeating errors, and actionable steps from the following Linux logs.
Return a concise markdown list with:
- Top problems (short title)
- Probable causes
- Suggested next commands to investigate (read-only)
EOF
DATA="$(printf "%s\n\nLogs:\n%s" "$PROMPT" "$(sed 's/"/\\"/g' /tmp/journal_excerpt.txt)")"
RESP="$(curl -s http://localhost:11434/api/generate -d @- <<JSON
{
"model": "$MODEL",
"prompt": "$DATA",
"options": { "temperature": 0.2 },
"stream": false
}
JSON
)"
SUMMARY="$(echo "$RESP" | jq -r '.response')"
echo "=== $(date) ===" >> $HOME/offline_log_summaries.md
echo "$SUMMARY" >> $HOME/offline_log_summaries.md
echo >> $HOME/offline_log_summaries.md
Make executable:
chmod +x ~/bin/offline_log_summary.sh
Option A: systemd user timer (no root needed):
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/offline-log-summary.service <<'UNIT'
[Unit]
Description=Offline log summary via local LLM
[Service]
Type=oneshot
ExecStart=%h/bin/offline_log_summary.sh
UNIT
cat > ~/.config/systemd/user/offline-log-summary.timer <<'UNIT'
[Unit]
Description=Run offline log summary daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
UNIT
systemctl --user daemon-reload
systemctl --user enable --now offline-log-summary.timer
Option B: cron (system-wide):
crontab -e
# Add:
@daily $HOME/bin/offline_log_summary.sh >> $HOME/offline_log_summary.log 2>&1
Real-world examples you can build next
1) Voice-driven maintenance:
“Update package index” (read-only check first):
- Debian/Ubuntu:
apt update --print-uris - Fedora/RHEL:
dnf check-update - openSUSE:
zypper refresh --force
- Debian/Ubuntu:
You can allow write operations only after a second explicit confirmation.
2) Local knowledge base Q&A:
- Point the LLM at
/var/log, config directories, or project docs. Use retrieval augmented generation (RAG) with a local vector DB (e.g., sqlite + embeddings generated offline).
3) Air-gapped CI helper:
- Summarize test logs, suggest failing areas, propose targeted
greporpytest -kinvocations—no outbound requests.
Performance tips
Choose the right size: 3B–7B instruction-tuned models are great for command generation and summaries on CPU-only machines.
Quantization: Use Q4_K_M or similar for speed on modest hardware.
Threading: Set
OMP_NUM_THREADS=$(nproc)or equivalent for llama.cpp/whisper.cpp if needed.GPU acceleration: llama.cpp and whisper.cpp support CUDA/Metal/ROCm builds; enable if you have the hardware.
Troubleshooting
Microphone device:
- List devices:
arecord -l - Choose device:
arecord -D plughw:0,0 -f S16_LE -r 16000 -c 1 /tmp/clip.wav -d 5
- List devices:
Ollama not running:
systemctl status ollama(orjournalctl -u ollama)
Model too slow:
- Try a smaller or more aggressively quantized model.
Whisper accuracy:
- Use a larger model (e.g.,
small.en) or speak closer to the mic.
- Use a larger model (e.g.,
Conclusion and next steps
You now have an end-to-end, completely offline AI stack on Linux:
Local LLM via Ollama or llama.cpp
Local speech-to-text via whisper.cpp
Bash glue that turns voice or text into safe, auditable automation
Schedulable jobs for continuous insights—no cloud needed
Call to action:
Start with the voice agent and keep DRY_RUN enabled.
Tighten allowlists and add unit tests for your automations.
Expand to log triage, config audits, or RAG over your docs—entirely offline.
Your Linux box just became an AI workstation that respects your privacy. Build something useful today.