Posted on
Artificial Intelligence

Building an Artificial Intelligence Linux Command Assistant

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

Building an AI Linux Command Assistant (in pure Bash)

Ever stared at a blinking cursor thinking “there has to be a one-liner for this…”? Imagine a shell companion that:

  • Translates natural language into precise Bash commands

  • Explains cryptic errors and logs

  • Offers safe “confirm before run” execution

  • Avoids catastrophic footguns by default

In this guide, you’ll build exactly that: a small Bash tool that talks to an LLM (cloud or local) and becomes your on-demand Linux command assistant.

Why this matters:

  • LLMs are great at transforming intent into shell incantations.

  • A thin Bash wrapper gives you reproducibility, auditability, and control (prompts, guardrails, dry-runs).

  • You keep your workflow in the terminal you already love.

What you’ll build

A single ai CLI with subcommands:

  • ai chat "…". Ask questions in natural language.

  • ai cmd "…". Get only the final Bash command (no prose).

  • ai run "…". Get a command, then confirm to execute it.

  • ai explain. Pipe output/logs and get a human-readable diagnosis.

  • ai fix <failing command …>. Run a command, capture the failure, and get a suggested fix.

Backends supported:

  • OpenAI (cloud) via API

  • Ollama (local) for private, offline-ish usage

Prerequisites and installation

1) Install required packages (curl and jq)

  • Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y curl jq ca-certificates
  • Fedora/RHEL/CentOS (dnf):
sudo dnf install -y curl jq ca-certificates
  • openSUSE (zypper):
sudo zypper install -y curl jq ca-certificates

2) Pick an AI backend

Option A — Cloud (OpenAI)

  • Get an API key from your OpenAI account.

  • Export environment variables (add these to ~/.bashrc to persist):

export AI_PROVIDER=openai
export OPENAI_API_KEY="sk-...your-key..."
# Pick a model name you have access to, e.g. gpt-4o or gpt-4o-mini
export AI_MODEL="gpt-4o-mini"

Option B — Local (Ollama)

  • Install Ollama:
curl -fsSL https://ollama.com/install.sh | sh
  • Start the service if needed:
sudo systemctl enable --now ollama
  • Pull a model (example: Llama 3, 8B):
ollama pull llama3:8b
  • Export environment variables:
export AI_PROVIDER=ollama
export AI_MODEL="llama3:8b"

3) Install the ai script

mkdir -p ~/.local/bin
nano ~/.local/bin/ai

Paste the script below, save, then:

chmod +x ~/.local/bin/ai
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

The assistant script

Paste this whole script into ~/.local/bin/ai:

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

# Configuration (override via environment)
: "${AI_PROVIDER:=openai}"      # openai | ollama
: "${AI_MODEL:=gpt-4o-mini}"    # For openai; use something like llama3:8b for ollama
: "${AI_TEMPERATURE:=0.2}"

SYSTEM_PROMPT_DEFAULT=$'You are a careful Linux shell assistant for experienced users.\n\
When asked for commands, reply with a minimal, safe, POSIX-compliant Bash one-liner first in a fenced code block, then a brief explanation.\n\
Never claim to have executed anything.\n\
If a command can be destructive (rm, dd, chmod -R, mkfs, chown -R, etc.), add a clear CAUTION and provide a dry-run or safer alternative.'
SYSTEM_PROMPT="${SYSTEM_PROMPT:-$SYSTEM_PROMPT_DEFAULT}"

# --- Backend adapters --------------------------------------------------------

_ai_call_openai() {
  local prompt=$1
  if [[ -z "${OPENAI_API_KEY:-}" ]]; then
    echo "ERROR: OPENAI_API_KEY is not set" >&2
    return 2
  fi

  # Build JSON and call OpenAI Chat Completions
  jq -n \
    --arg model "$AI_MODEL" \
    --arg sys "$SYSTEM_PROMPT" \
    --arg user "$prompt" \
    --argjson temp "$(printf '%s' "$AI_TEMPERATURE" | jq -R 'tonumber? // 0.2')" \
    '{
      model: $model,
      temperature: $temp,
      messages: [
        {role:"system", content:$sys},
        {role:"user", content:$user}
      ]
    }' \
  | curl -fsS https://api.openai.com/v1/chat/completions \
      -H "Authorization: Bearer ${OPENAI_API_KEY}" \
      -H "Content-Type: application/json" \
      -d @- \
  | jq -r '.choices[0].message.content // empty'
}

_ai_call_ollama() {
  local prompt=$1
  local model="${AI_MODEL:-llama3:8b}"
  local full_prompt="You are a Linux shell assistant.
$SYSTEM_PROMPT

User:
$prompt

Assistant:"

  jq -n \
    --arg model "$model" \
    --arg prompt "$full_prompt" \
    --argjson temp "$(printf '%s' "$AI_TEMPERATURE" | jq -R 'tonumber? // 0.2')" \
    '{model:$model, prompt:$prompt, stream:false, options:{temperature:$temp}}' \
  | curl -fsS http://localhost:11434/api/generate \
      -H "Content-Type: application/json" \
      -d @- \
  | jq -r '.response // empty'
}

_ai_call() {
  local prompt=$1
  case "$AI_PROVIDER" in
    openai) _ai_call_openai "$prompt" ;;
    ollama) _ai_call_ollama "$prompt" ;;
    *) echo "ERROR: Unsupported AI_PROVIDER: $AI_PROVIDER" >&2; return 2 ;;
  esac
}

# --- Public commands ---------------------------------------------------------

cmd_only_prompt() {
  # Tight prompt to force a single command, no noise.
  printf 'Output ONLY the final Bash command, with no backticks, no code fences, no comments, no explanations.\nTask: %s\n' "$1"
}

ai_chat() {
  local prompt
  if [ -t 0 ]; then
    prompt="$*"
  else
    prompt="$(cat)"
    [ -n "${*:-}" ] && prompt="${prompt}"$'\n'"$*"
  fi
  _ai_call "$prompt"
}

ai_cmd() {
  local prompt
  prompt="$(cmd_only_prompt "$*")"
  _ai_call "$prompt" | sed -e 's/^```.*$//' -e 's/^$//'
}

ai_run() {
  local cmd
  cmd="$(ai_cmd "$*")" || return
  if [[ -z "$cmd" ]]; then
    echo "No command returned." >&2
    return 1
  fi
  echo "Candidate command:"
  echo "$cmd"
  read -r -p "Run this command? [y/N] " ans
  if [[ "${ans,,}" == "y" ]]; then
    bash -c "$cmd"
  else
    echo "Aborted."
    return 1
  fi
}

ai_explain() {
  local input
  input="$(cat)"
  _ai_call "Explain the following Linux output/error like a senior sysadmin would, then propose a minimal, safe fix:\n\n$input"
}

ai_fix() {
  if [[ $# -eq 0 ]]; then
    echo "Usage: ai fix <failing command and args...>" >&2
    return 2
  fi
  set +e
  local output rc
  output="$("$@" 2>&1)"; rc=$?
  set -e
  if (( rc == 0 )); then
    echo "Command succeeded (exit $rc). Nothing to fix."
    return 0
  fi
  _ai_call "This command failed with exit code $rc. Diagnose and propose a corrected command ONLY (first), then a brief reason.\n\nCommand:\n$*\n\nOutput:\n$output"
}

# --- CLI dispatch ------------------------------------------------------------

sub="${1:-chat}"; shift || true
case "$sub" in
  chat)    ai_chat "$@" ;;
  cmd)     ai_cmd "$@" ;;
  run)     ai_run "$@" ;;
  explain) ai_explain ;;
  fix)     ai_fix "$@" ;;
  *) echo "Usage: ai [chat|cmd|run|explain|fix] [...]; see source for details." >&2; exit 2 ;;
esac

Notes:

  • The script defaults to OpenAI. Set AI_PROVIDER and AI_MODEL to switch.

  • All dangerous operations are discouraged by the system prompt, but you remain in control (especially via ai run).

How to use it (real-world examples)

  • Translate intent to command (preview safely)
ai chat "Recursively find files over 1G in /var but ignore /var/log"
  • Get just the command (no prose)
ai cmd "Recursively convert .jpeg to .jpg in current directory"
  • Confirm and run
ai run "Create a gzipped tar of ~/projects excluding node_modules and .git"
  • Explain weird output
dmesg | tail -n 200 | ai explain
  • Fix a failure
ai fix ls /root

Tips:

  • If the assistant proposes something destructive, it should also propose a dry-run. Prefer ai run so you can confirm.

  • Adjust temperature for more/less creativity:

export AI_TEMPERATURE=0.1
  • Tighten or customize behavior via SYSTEM_PROMPT:
export SYSTEM_PROMPT="Always return POSIX sh-compatible commands; prefer grep+awk+sed; never use sudo."

Why this pattern works

  • Minimal dependencies (curl + jq) keep the tool portable.

  • Backend-agnostic design lets you switch between cloud and local models.

  • “Command-only” mode and “confirm-to-run” mode separate generation from execution.

  • Explicit guardrails in the system prompt reduce risky output.

  • Each subcommand composes cleanly with Unix pipes.

Hardening ideas

  • Log all accepted commands to a local audit file.

  • Inject context from your machine (e.g., uname -a, distro, $SHELL) into the prompt when it helps.

  • Add a “dry-run” injection for known footguns automatically.

  • Run shellcheck on AI-generated scripts before execution.

  • Never run ai run as root unless absolutely necessary.

Conclusion and next steps

You’ve built a practical AI command assistant that stays in Bash, respects your workflow, and helps you move faster without sacrificing safety.

Where to go from here:

  • Wire this into your dotfiles and share with your team.

  • Add a subcommand that summarizes man pages or TLDR entries.

  • Cache frequent answers in ~/.cache/ai/.

  • Extend the provider to support other OpenAI-compatible endpoints.

Your terminal just got smarter—now put it to work on your next task.