- 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.