- Posted on
- • Artificial Intelligence
Artificial Intelligence Reporting Projects
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
AI-Powered Reporting Projects You Can Build in Bash (Today)
If your mornings start with grepping logs and scanning dashboards, you’re spending human attention on machine work. What if a tiny Bash script could pull your signals (health, security, code activity), ask an AI to summarize the noise, and hand you an executive-grade report every day?
This article shows you how to build practical “AI reporting” projects on Linux using Bash. You’ll get:
Why AI reporting is worth it
A drop-in Bash function to call either a local LLM (Ollama) or a cloud API
Three real-world reporting projects you can automate
Installation commands for apt, dnf, and zypper
Tips for scheduling, formatting, and safe operations
Why AI Reporting on Linux?
Time-to-signal: Logs, metrics, and commit histories are verbose. AI compresses them into high-signal summaries and action items.
Repeatable automation: A single script runs via cron/systemd, delivering a digest at the same time every day or week.
Flexible backends: Use local models for privacy (Ollama) or a cloud API for stronger reasoning (OpenAI) — switchable by an env var.
Native to your stack: Bash + standard CLI tools = zero vendor lock-in, easy review and diffing of generated reports.
Prerequisites and Installation
We’ll rely on a few standard tools. Install them with your package manager.
curl and jq (API calls + JSON processing)
pandoc (optional, to render HTML/PDF)
cron/cronie (scheduling)
git (for the Git report example)
Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y curl jq pandoc git cron
sudo systemctl enable --now cron
Fedora/RHEL (dnf):
sudo dnf install -y curl jq pandoc git cronie
sudo systemctl enable --now crond
openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y curl jq pandoc git cronie
sudo systemctl enable --now cron
Local LLM (Ollama) — optional but recommended for privacy:
curl -fsSL https://ollama.com/install.sh | sh
# Pull a model once:
ollama pull llama3
Cloud LLM (OpenAI) — optional:
Set your API key safely as an env var:
export OPENAI_API_KEY="sk-..."(don’t hardcode in scripts)Choose a model via
OPENAI_MODEL(example:gpt-4o-mini)
A Drop-in Bash Function: ai_summarize
Create this helper in ~/bin/ai_summarize.sh to call either Ollama or OpenAI with the same interface.
#!/usr/bin/env bash
# ai_summarize.sh
# Usage: ai_summarize "PROMPT" "INPUT"
set -euo pipefail
ai_summarize() {
local prompt="${1:-}"
local input="${2:-}"
local backend="${AI_BACKEND:-ollama}"
case "$backend" in
ollama)
local model="${OLLAMA_MODEL:-llama3}"
# Make sure model is available; non-fatal if already pulled
ollama pull "$model" >/dev/null 2>&1 || true
ollama run "$model" "$(printf '%s\n\nContext:\n%s\n' "$prompt" "$input")"
;;
openai)
: "${OPENAI_API_KEY:?Set OPENAI_API_KEY env var for openai backend}"
local model="${OPENAI_MODEL:-gpt-4o-mini}"
jq -n \
--arg p "$prompt" \
--arg i "$input" \
--arg m "$model" \
'{
model: $m,
messages: [
{role:"system", content:"You are a concise Linux reporting assistant. Output Markdown."},
{role:"user", content: ($p + "\n\nContext:\n" + $i)}
],
temperature: 0.2
}' \
| curl -sS 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'
;;
*)
echo "Unknown AI_BACKEND: $backend" >&2
return 1
;;
esac
}
# If sourced, export function; if executed directly, run with args
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
ai_summarize "$@"
else
export -f ai_summarize
fi
Make it executable and ensure your PATH includes ~/bin:
mkdir -p ~/bin
chmod +x ~/bin/ai_summarize.sh
Optional: keep settings in ~/.ai-report.env:
AI_BACKEND=ollama
OLLAMA_MODEL=llama3
# For OpenAI backend:
# OPENAI_API_KEY=...
# OPENAI_MODEL=gpt-4o-mini
Project 1: Daily Server Health Report (Markdown + optional HTML/Slack)
This script aggregates health signals, asks the AI to summarize, and writes a Markdown report you can also convert to HTML.
Save as ~/bin/ai_health_report.sh:
#!/usr/bin/env bash
set -euo pipefail
[[ -f "$HOME/.ai-report.env" ]] && source "$HOME/.ai-report.env"
source "$HOME/bin/ai_summarize.sh"
REPORT_DIR="$HOME/ai-reports/health"
mkdir -p "$REPORT_DIR"
HOST="$(hostname -f 2>/dev/null || hostname)"
NOW="$(date -Is)"
PROMPT="Create a concise daily server health report in Markdown with sections: Overview, Disk, Memory, CPU/Load, Notable Logs, Action Items. Prioritize clarity and concrete next steps."
# Collect signals
DISK="$(df -hT --exclude-type=tmpfs --exclude-type=devtmpfs)"
MEM="$(free -m)"
LOAD="$(uptime && ps -eo pid,comm,pcpu,pmem --sort=-pcpu | head -n 10)"
LOGS="$(journalctl --since '24 hours ago' -p warning..alert --no-pager -n 2000 || true)"
INPUT="$(cat <<'EOF'
=== Host ===
__HOST__
=== Disk (df -hT) ===
__DISK__
=== Memory (free -m) ===
__MEM__
=== CPU & Top Procs ===
__LOAD__
=== Recent Warnings/Errors (journalctl) ===
__LOGS__
EOF
)"
INPUT="${INPUT/__HOST__/$HOST}"
INPUT="${INPUT/__DISK__/$DISK}"
INPUT="${INPUT/__MEM__/$MEM}"
INPUT="${INPUT/__LOAD__/$LOAD}"
INPUT="${INPUT/__LOGS__/$LOGS}"
SUMMARY="$(ai_summarize "$PROMPT" "$INPUT")"
OUT_MD="$REPORT_DIR/${HOST}-health-$(date +%F).md"
{
echo "# ${HOST} — Daily Health Report"
echo "_Generated: ${NOW}_"
echo
echo "$SUMMARY"
} > "$OUT_MD"
# Optional: Convert to HTML (requires pandoc)
if command -v pandoc >/dev/null 2>&1; then
pandoc "$OUT_MD" -o "${OUT_MD%.md}.html" --metadata title="${HOST} Health Report"
fi
# Optional: Send to Slack (set SLACK_WEBHOOK_URL)
if [[ -n "${SLACK_WEBHOOK_URL:-}" ]]; then
# Escape Markdown as plain text; Slack supports simple Markdown-like formatting
payload="$(jq -n --arg text "$(cat "$OUT_MD")" '{text:$text}')"
curl -sS -X POST -H 'Content-type: application/json' --data "$payload" "$SLACK_WEBHOOK_URL" >/dev/null || true
fi
echo "Wrote: $OUT_MD"
Make it executable:
chmod +x ~/bin/ai_health_report.sh
Schedule it with cron:
Debian/Ubuntu (apt):
- Cron is already enabled above. Edit your crontab:
crontab -eAdd (runs at 06:15 daily):
15 6 * * * . $HOME/.ai-report.env; $HOME/bin/ai_health_report.sh >> $HOME/ai-reports/health/cron.log 2>&1Fedora/RHEL (dnf) and openSUSE (zypper):
- With cronie enabled above:
crontab -eAdd the same line:
15 6 * * * . $HOME/.ai-report.env; $HOME/bin/ai_health_report.sh >> $HOME/ai-reports/health/cron.log 2>&1
Tip: Keep sensitive info out of LOGS or redact before sending to a cloud API.
Project 2: SSH Security Anomaly Digest
Summarize failed logins, top source IPs, and suspicious patterns from the last 24 hours.
Save as ~/bin/ai_security_digest.sh:
#!/usr/bin/env bash
set -euo pipefail
[[ -f "$HOME/.ai-report.env" ]] && source "$HOME/.ai-report.env"
source "$HOME/bin/ai_summarize.sh"
REPORT_DIR="$HOME/ai-reports/security"
mkdir -p "$REPORT_DIR"
HOST="$(hostname -f 2>/dev/null || hostname)"
NOW="$(date -Is)"
PROMPT="Summarize SSH authentication anomalies from the last 24 hours. Include Top IPs, Attack Patterns, Impact/Risk, and Recommended Actions (commands in code blocks). Keep it concise and actionable."
# Collect logs (cover common unit names)
LOG="$(journalctl --since '24 hours ago' -u ssh -u sshd --no-pager -o short-iso || true)"
TOP_IPS="$(echo "$LOG" \
| grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' \
| sort | uniq -c | sort -nr | head -n 20 || true)"
FAIL_LINES="$(echo "$LOG" | grep -E 'Failed password|Connection closed|Invalid user' | tail -n 200 || true)"
INPUT="$(cat <<'EOF'
=== Host ===
__HOST__
=== Top Source IPs (counts) ===
__TOP_IPS__
=== Sample Failure Lines ===
__FAIL_LINES__
EOF
)"
INPUT="${INPUT/__HOST__/$HOST}"
INPUT="${INPUT/__TOP_IPS__/$TOP_IPS}"
INPUT="${INPUT/__FAIL_LINES__/$FAIL_LINES}"
SUMMARY="$(ai_summarize "$PROMPT" "$INPUT")"
OUT_MD="$REPORT_DIR/${HOST}-ssh-digest-$(date +%F).md"
{
echo "# ${HOST} — SSH Security Digest"
echo "_Generated: ${NOW}_"
echo
echo "$SUMMARY"
} > "$OUT_MD"
echo "Wrote: $OUT_MD"
Run it ad-hoc or schedule weekly:
crontab -e
# Fridays at 08:00
0 8 * * 5 . $HOME/.ai-report.env; $HOME/bin/ai_security_digest.sh >> $HOME/ai-reports/security/cron.log 2>&1
Note: For cloud AI, consider redacting internal usernames/IP ranges before sending.
Project 3: Weekly Git Repository Summary
Turn a week of commits into a manager-ready summary of what changed and where risk might be.
Save as ~/bin/ai_git_weekly.sh:
#!/usr/bin/env bash
set -euo pipefail
[[ -f "$HOME/.ai-report.env" ]] && source "$HOME/.ai-report.env"
source "$HOME/bin/ai_summarize.sh"
REPO="${1:?Usage: ai_git_weekly.sh /path/to/repo}"
cd "$REPO"
REPORT_DIR="$HOME/ai-reports/git"
mkdir -p "$REPORT_DIR"
NAME="$(basename "$REPO")"
NOW="$(date -Is)"
SINCE="${SINCE:-7 days ago}"
PROMPT="Produce a weekly engineering summary in Markdown: Highlights, Areas of Risk, Testing/Docs, Notable Files, and Next Steps. Be specific and concise."
COMMITS="$(git log --since="$SINCE" --pretty=format:'%h %an %ad %s' --date=short || true)"
AUTHORS="$(git shortlog -sne --since="$SINCE" || true)"
FILES="$(git log --since="$SINCE" --name-only --pretty=format: | sort | uniq -c | sort -nr | head -n 30 || true)"
INPUT="$(cat <<'EOF'
=== Repo ===
__NAME__
=== Commits (since __SINCE__) ===
__COMMITS__
=== Top Contributors ===
__AUTHORS__
=== Most-Touched Files ===
__FILES__
EOF
)"
INPUT="${INPUT/__NAME__/$NAME}"
INPUT="${INPUT/__SINCE__/$SINCE}"
INPUT="${INPUT/__COMMITS__/$COMMITS}"
INPUT="${INPUT/__AUTHORS__/$AUTHORS}"
INPUT="${INPUT/__FILES__/$FILES}"
SUMMARY="$(ai_summarize "$PROMPT" "$INPUT")"
OUT_MD="$REPORT_DIR/${NAME}-weekly-$(date +%F).md"
{
echo "# ${NAME} — Weekly Summary"
echo "_Generated: ${NOW}_"
echo
echo "$SUMMARY"
} > "$OUT_MD"
echo "Wrote: $OUT_MD"
Usage:
chmod +x ~/bin/ai_git_weekly.sh
~/bin/ai_git_weekly.sh ~/code/your-repo
Schedule it (Sundays at 17:30):
crontab -e
30 17 * * 0 . $HOME/.ai-report.env; $HOME/bin/ai_git_weekly.sh $HOME/code/your-repo >> $HOME/ai-reports/git/cron.log 2>&1
Formatting and Delivery Options
Convert Markdown to HTML (already in Project 1):
pandoc report.md -o report.htmlSlack webhooks:
- Set
SLACK_WEBHOOK_URL, then post JSON withcurlas shown in the health report script.
- Set
Static site:
- Serve
~/ai-reportsfrom Nginx or push to a Git repo/GitHub Pages.
- Serve
Practical Tips
Privacy first:
- Prefer Ollama (local) for sensitive logs; for cloud, redact obvious secrets and internal IP ranges.
Keep inputs bounded:
- Limit log lines (e.g.,
-n 2000), or summarize sections separately and stitch results.
- Limit log lines (e.g.,
Reproducibility:
- Save raw inputs next to the AI output for auditing:
tee "$OUT_MD.input.txt".
- Save raw inputs next to the AI output for auditing:
Fail safe:
- If AI call fails, still write a minimal report with raw metrics and a note.
Version prompts:
- Track prompt changes in Git so you can see when summaries improved or regressed.
Your Next Step (CTA)
Pick one project above and wire it into your environment today:
1) Install prerequisites via your package manager.
2) Drop in ai_summarize.sh and set AI_BACKEND to ollama or openai.
3) Run ai_health_report.sh once, inspect the output, then schedule it.
From there, customize prompts, add more signals, and make the AI do the boring reporting — so you can do the interesting engineering.