Scripting and Scheduling Local LLM Tasks: Python, Cron, and Systemd
Automating local Large Language Model (LLM) execution transforms manual prompt engineering into reliable, background-driven workflows. Whether you need to digest daily server logs, generate overnight summary digests, or re-index document vectors for retrieval-augmented generation (RAG) applications, manually triggering scripts via a web interface quickly becomes inefficient.
To build hands-free AI pipelines, developers rely on three core pillars of task automation: Python scripts for API orchestration, cron jobs for rapid scheduling, and systemd timers for enterprise-grade background service management.
In this guide, you will learn how to script and schedule local LLM tasks using Python, configure Linux and macOS cron schedules, implement robust systemd service units, and set up structured error logging to ensure your background jobs run reliably without intervention.
Prerequisites for Scripting Local LLM Tasks
Before automating local inference, your local setup must meet a few basic technical requirements:
- A Running Local Inference Backend: An active local AI server providing an HTTP REST API. Popular engines include Ollama (running on
http://localhost:11434), LM Studio (http://localhost:1234), or LocalAI (http://localhost:8080). - Python 3.9+ Environment: A standard Python installation with the
requestslibrary or an official client package installed (pip install requests schedule). (requestslibrary) - OS Access: Command-line terminal access on Linux or macOS with standard privileges to edit crontabs or create systemd configuration files.
Having an active API server ensures your python scripts can send inference payloads asynchronously without launching heavy graphical desktop interfaces.
How to Schedule LLM Inference Using Python
Python provides the ideal environment for formatting prompts, calling local HTTP endpoints, and saving model outputs to structured storage.

A Python script illustrating the use of the schedule library to automate LLM inference at specific intervals.
Writing the Script (Using requests or LLM wrappers)
The most direct way to execute inference in Python is sending HTTP POST requests to your local engine’s API endpoint. The script below reads an input text file, sends the content to a local Ollama server, and writes the generated summary to disk.
#!/usr/bin/env python3
"""
local_llm_runner.py
A Python script to send prompt tasks to a local LLM API.
"""
import os
import json
import requests
from datetime import datetime
# API Configuration
OLLAMA_ENDPOINT = "http://localhost:11434/api/generate"
MODEL_NAME = "llama3.2:latest"
OUTPUT_DIR = "/home/user/llm_reports"
def run_inference(prompt_text):
payload = {
"model": MODEL_NAME,
"prompt": prompt_text,
"stream": False,
"options": {
"temperature": 0.2,
"num_ctx": 4096
}
}
try:
response = requests.post(OLLAMA_ENDPOINT, json=payload, timeout=300)
response.raise_for_status()
data = response.json()
return data.get("response", "")
except requests.exceptions.RequestException as e:
print(f"[{datetime.now()}] API Error: {e}")
return None
def main():
os.makedirs(OUTPUT_DIR, exist_ok=True)
prompt = "Analyze system health and generate a 3-bullet summary: All services operational, CPU usage 22%, RAM usage 45%."
result = run_inference(prompt)
if result:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filepath = os.path.join(OUTPUT_DIR, f"report_{timestamp}.txt")
with open(filepath, "w", encoding="utf-8") as f:
f.write(result)
print(f"[{datetime.now()}] Success: Saved report to {filepath}")
if __name__ == "__main__":
main()
Implementing the Python schedule Library
If you prefer pure Python process control over system-level task schedulers, you can use the lightweight schedule library. (schedule library) This approach allows your script to remain running continuously as a background process while executing functions on designated schedules.
import schedule
import time
from datetime import datetime
def job():
print(f"[{datetime.now()}] Starting scheduled local LLM execution...")
# Import or execute your inference workflow here
# run_inference("Daily task prompt...")
# Schedule options
schedule.every().day.at("02:00").do(job) # Run nightly at 2:00 AM
schedule.every(4).hours.do(job) # Run every 4 hours
print("LLM Scheduler service started. Press Ctrl+C to exit.")
while True:
schedule.run_pending()
time.sleep(60)
While using Python’s schedule library is straightforward, continuous process loops will stop if the machine reboots or encounters an unhandled exception. For mission-critical tasks, combining your Python script with OS-level tools like cron or systemd provides significantly better reliability.
Setting up a Cron Job for a Local LLM (Linux/macOS)
cron is the standard time-based job scheduler in Unix-like operating systems. It runs in the background and checks configuration files (crontabs) every minute to trigger commands at specified times.

A terminal interface displaying a crontab entry, configured to schedule a local LLM task for automated execution.
To open your current user’s crontab editor, run:
crontab -e
Example Cron Expressions for Nightly Runs
A standard crontab entry consists of five time fields followed by the path to your executable shell command:
# Minute Hour Day-of-Month Month Day-of-Week Command
0 2 * * * /usr/bin/python3 /home/user/scripts/local_llm_runner.py >> /home/user/logs/cron_llm.log 2>&1
Here are common cron schedule expressions useful when scheduling local AI tasks:
| Schedule Syntax | Execution Frequency | Primary Use Case |
|---|---|---|
0 2 * * * |
Every night at 2:00 AM | Ideal for running AI models overnight without impacting daytime work. |
0 */4 * * * |
Every 4 hours on the hour | Periodic processing of incoming support emails or log batches. |
30 6 * * 1-5 |
Monday through Friday at 6:30 AM | Pre-generating morning executive summaries before office hours. |
@reboot |
Once upon system startup | Ensuring continuous API wrappers or schedulers launch automatically after boot. |
Important Cron Rule: Always use absolute file paths (e.g., /usr/bin/python3 instead of python3) inside cron entries because cron executes commands within a bare minimal environment without your standard user PATH variables.
For workflows specifically targeted at Ollama servers, check out our guide on automating Ollama endpoints to learn how to pair bash cURL requests with cron triggers.
Creating a Systemd Timer for Robust Background Tasks
While cron works well for simple tasks, Linux distributions using systemd benefit from systemd timers. Systemd timers offer several distinct advantages over traditional cron jobs:
- Resource Control: Limit CPU and VRAM usage using cgroups.
- Service Dependencies: Ensure the network and local LLM backend server (e.g., Ollama systemd service) are fully online before triggering the task script.
- Logging Integration: Automatic stdout and stderr logging piped directly to
journalctl.
Setting up a systemd timer requires two files placed in /etc/systemd/system/: a service file and a timer file.
Step 1: Create the Service File (/etc/systemd/system/llm-task.service)
[Unit]
Description=Execute Scheduled Local LLM Inference Task
After=network.target ollama.service
[Service]
Type=oneshot
User=user
WorkingDirectory=/home/user/scripts
ExecStart=/usr/bin/python3 /home/user/scripts/local_llm_runner.py
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Step 2: Create the Timer File (/etc/systemd/system/llm-task.timer)
[Unit]
Description=Run LLM Task Nightly at 2 AM
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
Step 3: Enable and Activate the Timer
Reload the systemd manager configuration, enable the timer to persist across reboots, and start it immediately:
sudo systemctl daemon-reload
sudo systemctl enable llm-task.timer
sudo systemctl start llm-task.timer
To verify the status and next scheduled execution time of your timer, run:
systemctl list-timers llm-task.timer
Logging Output and Capturing Execution Errors
Because scheduled tasks run unattended in the background, robust logging is essential to diagnose failures, monitor token generation performance, and verify outputs.
1. Redirecting Standard Streams in Cron
When using cron, always redirect standard output (stdout) and standard error (stderr) to a log file:
0 2 * * * /usr/bin/python3 /path/to/script.py >> /var/log/llm_tasks.log 2>&1
2. Querying Systemd Logs with journalctl
When using systemd services, logs are automatically captured by systemd’s logging daemon. You can inspect your script’s execution history using journalctl:
# View all log entries for the LLM task service
sudo journalctl -u llm-task.service
# Stream logs in real-time
sudo journalctl -u llm-task.service -f --since "1 hour ago"
3. Implementing Python Exception Handlers
Always wrap network requests, filesystem reads, and JSON parsing in try-except blocks. If the local AI inference engine is restarting or updating, your script should log the error cleanly, return a non-zero exit code for systemd/cron tracking, and retry gracefully.
import sys
import logging
logging.basicConfig(
filename='/var/log/llm_python_runner.log',
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s'
)
try:
# Perform LLM request...
logging.info("Task completed successfully.")
except Exception as err:
logging.error(f"Execution failed: {err}", exc_info=True)
sys.exit(1) # Return error code to system scheduler
Mastering Python orchestration alongside system-level utilities like cron and systemd ensures your local AI infrastructure operates with high reliability, minimal maintenance, and zero hands-on overhead.
Frequently Asked Questions (FAQ)
Why is my cron job for a local LLM not running?
The most common cause of cron job failure is environment path misconfiguration. Cron executes commands in a minimal environment, meaning standard environment variables and binary PATHs are not loaded. Ensure you use absolute paths for both the Python executable (/usr/bin/python3) and your script path (/home/user/script.py). Additionally, verify that the cron log directory exists and is writable by the user.
Is systemd or cron better for scheduling local LLM scripts?
While cron is quicker to set up for simple tasks, systemd timers are generally better for local LLM pipelines. Systemd allows you to set explicit dependencies (e.g., waiting for the local LLM daemon process to start first), offers built-in log rotation via journalctl, and provides options like Persistent=true to immediately run missed jobs if the system was powered off at the scheduled time.
Can I run Python schedule scripts as a system background service?
Yes. You can write a continuous Python script using the schedule or APScheduler libraries and turn it into a background service using systemd or tools like nohup / tmux. However, for long-term production use, triggering single-execution Python scripts via systemd timers is generally more memory-efficient than keeping a Python interpreter process continuously running in RAM.
How do I verify my local LLM API server is online before running my script?
You can add a preliminary check function in Python using requests.get() to ping the engine’s health endpoint (e.g., http://localhost:11434/ for Ollama). If the server responds with an HTTP 200 status code, proceed with inference; otherwise, log a warning and exit cleanly or wait and retry.