I Run 10+ AI Workers on Bash Scripts — Here's Why I Don't Use Python
Everyone told me I was crazy.
"You're building autonomous AI agents... in bash?"
Yes. And they've been running 24/7 for weeks, managing freelance proposals, tracking revenue, monitoring GitHub repos, and publishing content — all without a single pip install.
Here's why I chose bash, when Python is actually better, and the real lesson about picking tools.
The Setup
I run an AI agent called koi that coordinates multiple "workers" — small programs that each handle a specific task:
- koi-worker-openwork: Searches freelance platforms and submits proposals
- koi-github-fork-worker: Forks repos, generates improvements, creates PRs
- koi-metrics: Collects weekly metrics across all platforms
- koi-finance: Tracks income and expenses in CSV
Each worker is a bash script. Some are 50 lines. The biggest is around 200.
Why Bash Won
1. Zero Dependencies
#!/bin/bash
# This works on any Linux machine. Period.
curl -s "https://api.github.com/repos/owner/repo" | python3 -c "import json,sys; print(json.load(sys.stdin)['stargazers_count'])"
No virtual environments. No requirements.txt. No "works on my machine." If the system has bash, curl, and python3 (for JSON parsing), it runs.
2. Systemd Timers Are Native
# /etc/systemd/system/koi-worker.timer
[Unit]
Description=Run koi worker every 15 minutes
[Timer]
OnBootSec=2m
OnUnitActiveSec=15m
RandomizedDelaySec=30
[Install]
WantedBy=timers.target
Systemd speaks bash natively. No Celery. No APScheduler. No cron syntax to remember. Just a timer unit that runs a script.
3. Piping Is Superpowers
# Get trending repos → filter → format → post to Telegram
curl -s "$API/search/repositories?q=topic:ai&sort=stars" \
| python3 -c "import json,sys; [print(f'{i[0]}: {i[1]}⭐') for i in [(r['full_name'], r['stargazers_count']) for r in json.load(sys.stdin)['items'][:5]]]" \
| tee /tmp/trending.txt \
| xargs -I{} curl -s "https://api.telegram.org/bot$TOKEN/sendMessage" -d "chat_id=$CHAT_ID&text={}"
Try doing that in Python with the same readability. Go ahead.
4. Debugging Is Just... Reading
set -x # Enable debug mode
# Every command prints before executing
# Or just:
bash -x ./worker.sh 2>&1 | tee debug.log
No pdb. No breakpoints. No IDE needed. The script tells you exactly what it's doing.
When Python Wins
I'm not a bash fanboy. Python is objectively better for:
Complex Data Structures
# Try maintaining this in bash
workers = {
"openwork": {"interval": 900, "last_run": 1718601600, "status": "ok"},
"github": {"interval": 86400, "last_run": 1718515200, "status": "ok"},
}
Bash has associative arrays. They're terrible. Use Python.
API Clients with Auth
import requests
from requests_oauthlib import OAuth1Session
# OAuth in bash? Technically possible. Actually? Painful.
Error Handling
try:
result = risky_operation()
except RateLimitError:
time.sleep(60)
result = risky_operation()
except Exception as e:
logger.error(f"Failed: {e}")
raise
Bash error handling is set -e and prayer.
Testing
def test_worker_parses_response():
mock_response = {"items": [{"full_name": "test/repo"}]}
result = parse_trending(mock_response)
assert result[0]["name"] == "test/repo"
You can test bash. You won't enjoy it.
The Hybrid Approach (What I Actually Do)
The secret is: I use both.
#!/bin/bash
# Worker orchestrator in bash
# Heavy lifting in Python
# Bash: orchestration, file I/O, system calls
for worker in workers/*.sh; do
bash "$worker" &
done
# Python: data processing
python3 scripts/parse_results.py /tmp/worker_output.json
# Bash: notification
curl -s "https://api.telegram.org/bot$TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID&text=$(cat /tmp/summary.txt)"
The rule:
- Bash for glue code, orchestration, file operations, system calls
- Python for data processing, API clients, anything with complex logic
- Systemd for scheduling (not cron, not Celery)
The Real Lesson
The best tool isn't the most elegant. It's the one that:
- Solves the problem — not "could solve" but does
- You can debug at 3am — when it breaks (not if)
- Runs anywhere — no setup, no dependencies
- You can read in 6 months — maintenance matters
For my workers, bash checks all four boxes. For my data pipeline, Python does.
Stop arguing about languages. Start solving problems.
Building autonomous agents is messy, iterative, and humbling. If you're on the same journey, I share everything openly — the code, the failures, the numbers.
Top comments (0)