Posted on
Artificial Intelligence

Building an Artificial Intelligence Linux Portfolio

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

Building an Artificial Intelligence Linux Portfolio (with Bash at the Core)

Want a portfolio that proves you can ship real AI on real machines? Build it on Linux. Recruiters and hiring managers love candidates who can wrangle models, automate pipelines, and deploy stable services with nothing but a terminal and a text editor. This article shows you how to assemble a credible, hands-on AI portfolio using Linux and Bash—complete with reproducible environments, local inference, training, benchmarking, and automation.

What you’ll get:

  • A clear why: the value of a Linux-native AI portfolio.

  • 3–5 actionable steps to build it.

  • Copy-pasteable commands for apt, dnf, and zypper package managers.

  • Real Bash and Python snippets you can adapt immediately.

Why a Linux AI portfolio matters

  • Employers want signal. Public repos with runnable scripts, Makefiles, and CI show you can do the work, not just talk about it.

  • Linux is where AI runs. From servers to edge devices, the AI stack is Linux-first: reproducible builds, systemd services, containers, GPUs, BLAS, and more.

  • Bash is the backbone. Data movement, environment setup, orchestration, and automation are all faster and more reliable in shell-based workflows.

  • Offline and local-first skills stand out. Many orgs need private inference, controlled dependencies, and on-prem pipelines. Demonstrate it.

1) Provision a reproducible AI workstation

Install essential build tools, Python, and utilities you’ll use across all projects. Use the commands appropriate for your distro.

  • Ubuntu/Debian (apt):
sudo apt update
sudo apt install -y \
  build-essential git curl wget cmake pkg-config \
  python3 python3-venv python3-pip python3-dev \
  libopenblas-dev jq unzip hyperfine podman docker.io pipx
  • Fedora/RHEL/CentOS (dnf):
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y \
  git curl wget cmake pkgconf-pkg-config \
  python3 python3-pip python3-devel \
  openblas-devel jq unzip hyperfine podman moby-engine pipx
  • openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y \
  gcc gcc-c++ make git curl wget cmake pkg-config \
  python3 python3-pip python3-devel \
  openblas-devel jq unzip hyperfine podman docker pipx

Tip: If pipx isn’t available or you prefer user-level install:

python3 -m pip install --user pipx
python3 -m pipx ensurepath

Create a Python virtual environment for your portfolio:

mkdir -p ~/ai-portfolio && cd ~/ai-portfolio
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip wheel
# Core scientific stack + Jupyter
python -m pip install numpy pandas scikit-learn matplotlib jupyterlab
# CPU-only PyTorch (adjust version as needed)
python -m pip install "torch==2.3.*" --index-url https://download.pytorch.org/whl/cpu

Optional, but recommended (linters and hooks):

pipx install pre-commit ruff

Initialize a clean repo:

git init
echo ".venv/" >> .gitignore
git add .gitignore
git commit -m "Initial commit: repo scaffold"

2) Project: A shell-first, automated data pipeline

Show you can fetch, validate, transform, and schedule data jobs with Bash. This is the glue that keeps ML systems healthy.

Example pipeline script:

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

ROOT="${ROOT:-$HOME/ai-portfolio}"
DATA_DIR="$ROOT/data"
RAW="$DATA_DIR/raw.csv"
CLEAN="$DATA_DIR/clean.csv"
LOGS_DIR="$ROOT/logs"

mkdir -p "$DATA_DIR" "$LOGS_DIR"

URL="https://example.com/datasets/sample.csv"
CHECKSUM_EXPECTED="abc123...put_real_sha256_here..."

echo "[INFO] Downloading dataset..."
curl -fSL "$URL" -o "$RAW"

echo "[INFO] Verifying checksum..."
echo "${CHECKSUM_EXPECTED}  ${RAW}" | sha256sum -c -

echo "[INFO] Cleaning data with awk..."
awk -F, 'NR==1 || ($3!="" && $4!="") {print $0}' "$RAW" > "$CLEAN"

echo "[INFO] Summary with jq (if JSON later) and wc..."
wc -l "$CLEAN"

Make it executable and test:

chmod +x pipeline.sh
./pipeline.sh

Schedule with cron:

crontab -e
# Add:
15 2 * * * /home/$(whoami)/ai-portfolio/pipeline.sh >> /home/$(whoami)/ai-portfolio/logs/pipeline.log 2>&1

Or create a user systemd timer (more robust than cron):

~/.config/systemd/user/ai-pipeline.service

[Unit]
Description=AI Portfolio Data Pipeline

[Service]
Type=oneshot
Environment=ROOT=%h/ai-portfolio
ExecStart=%h/ai-portfolio/pipeline.sh
WorkingDirectory=%h/ai-portfolio

~/.config/systemd/user/ai-pipeline.timer

[Unit]
Description=Run AI Portfolio Data Pipeline daily

[Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true

[Install]
WantedBy=timers.target

Enable:

systemctl --user daemon-reload
systemctl --user enable --now ai-pipeline.timer
systemctl --user status ai-pipeline.timer

3) Project: Run a local LLM with llama.cpp

Local inference is a standout skill—especially when you can compile, serve, and script models entirely offline.

Build llama.cpp:

cd ~/ai-portfolio
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
make -j

Download a small GGUF model (example using Hugging Face CLI):

pipx install huggingface_hub
# You may need to restart your shell or ensure ~/.local/bin is in PATH
huggingface-cli download TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF \
  tinyllama-1.1b-chat.Q4_K_M.gguf --local-dir ./models

Run a prompt:

./main -m ./models/tinyllama-1.1b-chat.Q4_K_M.gguf -p "Write a haiku about Linux."

Expose an HTTP endpoint and curl it:

./server -m ./models/tinyllama-1.1b-chat.Q4_K_M.gguf --host 0.0.0.0 --port 8080
# In another terminal:
curl -s -X POST http://127.0.0.1:8080/completion \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"Hello from Bash!","n_predict":128}' | jq -r .content

Notes:

  • For better CPU performance, read llama.cpp docs about BLAS builds. For NVIDIA GPUs, you can build with cuBLAS, but follow official CUDA setup for your distro.

  • Script your runs (reproducibility matters):

#!/usr/bin/env bash
set -euo pipefail
MODEL="${1:-./models/tinyllama-1.1b-chat.Q4_K_M.gguf}"
PROMPT="${2:-"Explain overfitting in one paragraph."}"
./main -m "$MODEL" -p "$PROMPT" -n 200

4) Project: Train and package a small model

Demonstrate you can go end-to-end: train, evaluate, save, and expose a clean CLI.

train.py:

#!/usr/bin/env python
import argparse, joblib
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, accuracy_score

def main():
    p = argparse.ArgumentParser()
    p.add_argument("--out", default="artifacts/model.joblib")
    args = p.parse_args()

    X, y = load_iris(return_X_y=True, as_frame=True)
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=42)

    clf = LogisticRegression(max_iter=1000, n_jobs=1)
    clf.fit(Xtr, ytr)
    preds = clf.predict(Xte)
    acc = accuracy_score(yte, preds)
    print("Accuracy:", acc)
    print(classification_report(yte, preds))

    import os
    os.makedirs("artifacts", exist_ok=True)
    joblib.dump(clf, args.out)
    print("Saved:", args.out)

if __name__ == "__main__":
    main()

requirements.txt:

scikit-learn
joblib
numpy
pandas
matplotlib

Bash CLI wrapper (cli.sh):

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$ROOT/.venv/bin/activate"
python "$ROOT/train.py" "$@"

Makefile to standardize commands:

.PHONY: setup train clean

setup:
    python -m pip install -U pip wheel
    python -m pip install -r requirements.txt

train:
    bash ./cli.sh --out artifacts/model.joblib

clean:
    rm -rf artifacts __pycache__

Run:

source .venv/bin/activate
make setup
make train

Benchmark training or inference to show empirical rigor:

hyperfine --warmup 1 'bash ./cli.sh --out /tmp/model1.joblib'

5) Ship it: containers, CI, and services

Containerize your project for portability. Podman is rootless by default and works great on all major distros.

Containerfile (Dockerfile-compatible):

FROM python:3.11-slim
RUN apt-get update && apt-get install -y --no-install-recommends libopenblas0 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["bash", "-lc", "python train.py --out artifacts/model.joblib && tail -f /dev/null"]

Build and run (Podman):

podman build -t ai-portfolio:latest .
podman run --rm -it -p 8088:8088 -v "$(pwd)/artifacts:/app/artifacts" ai-portfolio:latest

Build and run (Docker):

sudo systemctl enable --now docker
docker build -t ai-portfolio:latest .
docker run --rm -it -p 8088:8088 -v "$(pwd)/artifacts:/app/artifacts" ai-portfolio:latest

Pre-commit hooks (keeps your repo clean):

cat > .pre-commit-config.yaml << 'YAML'
repos:

- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.5.0
  hooks:
  - id: ruff
  - id: ruff-format

- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.6.0
  hooks:
  - id: end-of-file-fixer
  - id: trailing-whitespace
YAML

pre-commit install
pre-commit run --all-files

GitHub Actions CI (python-tests.yml):

name: python
on:
  push: { branches: ["main"] }
  pull_request:
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-python@v5
      with: { python-version: "3.11" }
    - run: python -m pip install -U pip wheel
    - run: python -m pip install -r requirements.txt ruff
    - run: ruff check .
    - run: python train.py --out artifacts/ci-model.joblib

Turn any script into a background service with systemd (user mode) as shown in Step 2. This proves you can run reliable, restartable workloads—exactly what teams need in production-like environments.

Real-world portfolio structure

ai-portfolio/
├─ pipeline.sh
├─ llama.cpp/                     # local LLM build (git submodule or cloned)
├─ data/                          # data assets (git-ignored if large)
├─ artifacts/                     # models and outputs
├─ train.py
├─ cli.sh
├─ requirements.txt
├─ Makefile
├─ Containerfile
├─ .pre-commit-config.yaml
└─ .github/workflows/python-tests.yml

Add a README that includes:

  • One-line project purpose.

  • Quickstart commands.

  • Hardware assumptions (CPU/GPU).

  • Example outputs and screenshots (curl to LLM server, training accuracy).

  • Benchmarks (paste hyperfine output).

Conclusion and next steps (CTA)

You now have all the moving parts to showcase genuine, hands-on AI engineering on Linux:

  • A reproducible environment.

  • A Bash-driven data pipeline.

  • Local LLM inference with llama.cpp.

  • A small but complete training workflow with packaging and benchmarks.

  • Containers, CI, and services for credibility.

Next steps:

  • Push your repo to GitHub/GitLab and make the README irresistible.

  • Write a short blog post per project explaining trade-offs and lessons learned.

  • Add a GPU track (CUDA or ROCm) and compare benchmarks.

  • Extend the LLM service with a tiny frontend or a CLI tool that pipes prompts from Bash.

Your terminal is your portfolio. Start shipping.