- Posted on
- • Artificial Intelligence
Artificial Intelligence Workflow Projects
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
AI Workflow Projects on Linux: From Notebook to Repeatable Pipelines with Bash
You don’t need a fleet of cloud services or heavyweight orchestration to ship machine learning reliably. With Bash, Make, and containers, you can build reproducible AI workflows that run on any Linux box—laptop to server—using tools you already trust.
The problem: Notebooks are great for exploration, but they often fail when you need to run the same steps tomorrow, on another machine, or inside a CI pipeline. The value: Turn your one-off experiments into predictable, versioned, testable workflows with a few small scripts and standard Linux utilities.
This post shows you a concrete, end-to-end example: fetching data with curl and jq, preparing features with Bash, training with Python, packaging with containers, and automating with cron.
Why a Bash-first AI workflow is a great fit
Deterministic and transparent: Each step is a plain command you can read, audit, and re-run.
Reproducible anywhere: If it runs in a terminal, it runs in CI and in containers.
Minimal dependencies: Uses standard Linux tools; no need for complex orchestrators to start.
Composable: Makefiles and scripts let you chain tasks, pass artifacts, and track results.
Prerequisites: Install core tools
Install system packages with your distro’s package manager. Choose either Podman (rootless by default) or Docker as your container engine.
Core tools (git, make, Python, pip, jq, curl):
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y git make python3 python3-venv python3-pip jq curl
- Fedora/RHEL (dnf):
sudo dnf install -y git make python3 python3-pip jq curl
- openSUSE (zypper):
sudo zypper install -y git make python3 python3-pip python3-virtualenv jq curl
Container engine (choose one):
Podman
- apt:
sudo apt install -y podman- dnf:
sudo dnf install -y podman- zypper:
sudo zypper install -y podmanDocker
- apt:
sudo apt install -y docker.io sudo systemctl enable --now docker sudo usermod -aG docker $USER newgrp docker- dnf (Fedora provides Docker via moby-engine):
sudo dnf install -y docker sudo systemctl enable --now docker sudo usermod -aG docker $USER newgrp docker- zypper:
sudo zypper install -y docker sudo systemctl enable --now docker sudo usermod -aG docker $USER newgrp docker
Cron (for scheduled automation):
- apt:
sudo apt install -y cron
sudo systemctl enable --now cron
- dnf:
sudo dnf install -y cronie
sudo systemctl enable --now crond
- zypper:
sudo zypper install -y cron
sudo systemctl enable --now cron
Project goal and dataset
We’ll build a tiny forecasting pipeline that:
Fetches hourly temperature data from the Open-Meteo API (no key needed)
Prepares a simple supervised dataset (predict next hour’s temperature from the current hour)
Trains a linear regression model
Packages inference into a container
Automates retraining with cron
Directory structure:
ai-workflow/
├── artifacts/ # trained model
├── data/ # raw and processed data
├── metrics/ # training metrics
├── scripts/ # bash helpers (fetch/prepare)
├── src/ # python code (train/predict)
├── Makefile
├── requirements.txt
└── Dockerfile
Step 1: Scaffold the project
Create folders and files:
mkdir -p ai-workflow/{artifacts,data/raw,data/processed,metrics,scripts,src}
cd ai-workflow
requirements.txt:
pandas
scikit-learn
joblib
Makefile:
SHELL := /usr/bin/env bash
ENGINE ?= podman
VENV := .venv
PY := $(VENV)/bin/python
.PHONY: setup data prepare train evaluate predict container clean
setup:
python3 -m venv $(VENV)
$(PY) -m pip install -U pip
$(PY) -m pip install -r requirements.txt
data:
bash scripts/fetch.sh data/raw/weather.json
prepare: data
bash scripts/prepare.sh data/raw/weather.json data/processed/features.csv
train: setup prepare
$(PY) src/train.py data/processed/features.csv artifacts/model.pkl metrics/metrics.json
evaluate:
jq . metrics/metrics.json
predict: train
echo 21.0 | $(PY) src/predict.py -
container: train
$(ENGINE) build -t ai-workflow:latest .
clean:
rm -rf $(VENV) artifacts metrics data
Step 2: Ingest and prepare with Bash + curl + jq
scripts/fetch.sh:
#!/usr/bin/env bash
set -euo pipefail
out="${1:-data/raw/weather.json}"
mkdir -p "$(dirname "$out")"
# Override via env: LAT=... LON=...
lat="${LAT:-52.52}" # Berlin
lon="${LON:-13.41}"
curl -fsSL \
"https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&hourly=temperature_2m&past_days=2&forecast_days=1&timezone=UTC" \
-o "$out"
echo "Wrote $out"
scripts/prepare.sh:
#!/usr/bin/env bash
set -euo pipefail
in="${1:-data/raw/weather.json}"
out="${2:-data/processed/features.csv}"
mkdir -p "$(dirname "$out")"
# Build a two-column CSV: current_temp, next_hour_temp
jq -r '
.hourly.temperature_2m as $t
| ["temp_t","temp_t_plus_1"],
(range(0; ($t|length - 1)) | [$t[.], $t[.+1]])
| @csv
' "$in" > "$out"
echo "Wrote $out"
Make them executable:
chmod +x scripts/*.sh
Test the ingestion:
make data
make prepare
head -n 5 data/processed/features.csv
Step 3: Train and evaluate the model
src/train.py:
import json, os, sys
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
import joblib
def main(in_csv, model_out, metrics_out):
df = pd.read_csv(in_csv)
X = df["temp_t"].values.reshape(-1, 1)
y = df["temp_t_plus_1"].values
n = int(0.8 * len(df))
X_train, X_test = X[:n], X[n:]
y_train, y_test = y[:n], y[n:]
model = LinearRegression().fit(X_train, y_train)
preds = model.predict(X_test)
mae = float(np.mean(np.abs(preds - y_test)))
os.makedirs(os.path.dirname(model_out), exist_ok=True)
joblib.dump(model, model_out)
os.makedirs(os.path.dirname(metrics_out), exist_ok=True)
with open(metrics_out, "w") as f:
json.dump({"mae": mae, "n_train": int(len(X_train)), "n_test": int(len(X_test))}, f)
print(f"Saved model to {model_out}")
print(f"Metrics: MAE={mae:.3f}")
if __name__ == "__main__":
in_csv, model_out, metrics_out = sys.argv[1], sys.argv[2], sys.argv[3]
main(in_csv, model_out, metrics_out)
src/predict.py:
import os, sys
import numpy as np
import joblib
# Usage:
# echo 21.0 | python src/predict.py -
# python src/predict.py 21.0
# MODEL_PATH can override the model location
model_path = os.environ.get("MODEL_PATH", "artifacts/model.pkl")
model = joblib.load(model_path)
def read_input():
if len(sys.argv) > 1 and sys.argv[1] != "-":
return float(sys.argv[1])
return float(sys.stdin.read().strip())
x = np.array([[read_input()]])
y = model.predict(x)[0]
print(y)
Run the pipeline:
make train
make evaluate
echo 22.5 | .venv/bin/python src/predict.py -
Step 4: Package inference in a container
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ /app/src/
COPY artifacts/model.pkl /app/artifacts/model.pkl
ENTRYPOINT ["python", "src/predict.py"]
Build and run with Podman:
make container # uses ENGINE=podman by default
echo 23.0 | podman run -i --rm ai-workflow:latest -
Or with Docker:
make container ENGINE=docker
echo 23.0 | docker run -i --rm ai-workflow:latest -
Tip: To use a different trained model at runtime, mount it and set MODEL_PATH:
echo 23.0 | podman run -i --rm -e MODEL_PATH=/m/model.pkl -v "$PWD/artifacts/model.pkl":/m/model.pkl:ro ai-workflow:latest -
Step 5: Automate retraining with cron
Add a cron job to fetch fresh data and retrain nightly. First, ensure cron is installed and running (see “Prerequisites” above).
Edit your user crontab:
crontab -e
Add a line (runs at 02:30 UTC daily):
30 2 * * * cd /path/to/ai-workflow && make train >> logs/cron.log 2>&1
Create the logs folder:
mkdir -p logs
Optional: Pin Python and system packages in CI, and have cron only kick off a containerized retrain to guarantee identical environments.
Real-world tips and extensions
Version everything: data snapshots, code, and artifacts. Tag releases after each successful training run.
Make targets composable: add
test,lint,qualityfor quick checks; wire them into CI.Track metrics: write JSONL per run with timestamp and git SHA to compare models.
Promote models: gate deployment steps on metric thresholds (e.g., MAE improved by X%).
Scale incrementally: when ready, wrap Make targets in a simple CI pipeline or use a lightweight queue. You can keep the same scripts.
Conclusion and next steps (CTA)
You’ve just built an end-to-end AI workflow using only Linux-native tools: Bash, Make, Python, and containers. It’s fast to run locally, easy to reason about, and ready for CI or cron.
Next steps:
Customize LAT/LON in scripts/fetch.sh to train on your region:
LAT=40.71 LON=-74.00 make trainAdd features (hour-of-day, moving averages) in scripts/prepare.sh and retrain
Expose predictions via a tiny FastAPI app and extend the Dockerfile
Wire make targets into GitHub Actions or GitLab CI for continuous training
Small, composable pieces beat complicated stacks when you’re moving fast. Start here, iterate, and scale only when you need to.