Tutorial: Simon Willison's llm CLI for log triage via Unix pipes

Simon Willison's llm CLI used in Unix pipelines to summarise system logs, llm-ollama plugin for local use, preventive redaction of sensitive data before sending to the model.

Open SourceAITutorial Open SourceAIAgenticTutorialllm-cliCLIMSPLogs

Preliminary notes

Content provided “as-is”. Before using llm in production:

  • Validate on test logs or in a sandbox.
  • Never place secrets into prompts. llm ships stdin to the configured provider.
  • Redact first: application logs can contain user emails, source IPs, session tokens, paths with customer names. Filter before piping.
  • For regulated environments use only a plugin pointing to a local model (Ollama, llamafile) — never a cloud endpoint.
  • llm keeps a local SQLite history (~/.config/io.datasette.llm/logs.db on Linux; ~/Library/Application Support/io.datasette.llm/logs.db on macOS): treat it as sensitive material.

What llm is

llm is a Python CLI released by Simon Willison with v0.1 on 1 April 2023 (llm.datasette.io). It is Apache 2.0 and follows a Unix-tool philosophy: one command that reads stdin, applies a prompt and writes to stdout. What matters for system administrators is the plugin system: the same llm can talk to OpenAI, Anthropic, Mistral, Gemini, local Ollama (via the llm-ollama plugin by Sergey Alexandrov, v0.1.0 released on 20 January 2024), llamafile, Hugging Face models — depending on the plugin installed.

The result is a tool composable with classic pipes (|, xargs, tee) and the rest of the shell toolbox. No UI, no tracking, no provider lock-in.

Use case: fast journalctl triage across a cluster

An MSP manages 20 Linux hosts. A report comes in: “some services seem unstable”. We want a script that, for each host, collects recent systemd errors, asks the model for a summary, and stores a report.

1. Install

# Option 1 — pipx, user space:
pipx install llm

# Option 2 — dedicated virtualenv:
python3 -m venv ~/.venvs/llm
source ~/.venvs/llm/bin/activate
pip install llm

llm --version

2. Local (Ollama) plugin to avoid cloud

llm install llm-ollama
# Ollama already running:
ollama pull mistral:7b   # or another appropriately-sized model
llm models default "Ollama: mistral:7b"

# Smoke test:
echo "hello" | llm

From now on, any llm invocation without provider flags hits the local model. No outbound traffic.

3. Per-host triage pipeline

Collect recent systemd errors, redact hostname and emails, pipe to the model:

HOST=srv-web-03
ssh "$HOST" "journalctl -p err -S '24 hours ago' --no-pager" \
  | sed -E "s/$HOST/[HOST]/g; s/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/[EMAIL]/g" \
  | llm -s "Analyse these systemd logs. Group by unit, identify the top 3 recurring issues, suggest concrete diagnostic checks. Do not invent anything not present in the logs." \
  > "reports/$HOST-$(date +%F).md"

Notes:

  • -s (--system) sets the system prompt; log body is the user prompt via stdin.
  • sed redacts hostname and emails before they reach the model. Extend with regex for your own conventions (e.g. [CLIENT-xxx]).
  • Output goes to reports/, one file per host: committable to a private git, diffable across time.

4. Batch across hosts in parallel

mkdir -p reports
cat hosts.txt | xargs -P 4 -I {} bash -c '
HOST="$1"
ssh "$HOST" "journalctl -p err -S '\''24 hours ago'\'' --no-pager" \
  | sed -E "s/$HOST/[HOST]/g; s/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/[EMAIL]/g" \
  | llm -s "Analyse these systemd logs..." \
  > "reports/$HOST-$(date +%F).md"
' _ {}

-P 4 caps parallelism at 4 concurrent SSH sessions, avoiding saturating the local model. Tune concurrency to the load Ollama handles on your hardware.

5. Queryable archive

llm logs returns all past prompts/responses:

llm logs -n 10
llm logs list -q "nginx"   # search history

The history is in SQLite: for an MSP it is an operator log to back up and rotate like the others. And, like the others, it contains sensitive content: ~/.config/io.datasette.llm/ must be protected with restrictive permissions.

Limits and caveats

  • Regex redaction is fragile: a sed-based filter does not cover every PII form. For personal-data environments, structured redaction (e.g. Presidio) must happen before the model — and still only locally.
  • Local models can be slow: a 7B on CPU responds in seconds; across a wide fleet the bottleneck is real. Scale with GPU or use smaller models for triage.
  • Prompt injection inside logs: if a log contains text that “looks like” an instruction, the model may interpret it. A documented prompt injection form. Do not rely on the summary alone to take critical actions.
  • Not a SIEM replacement: llm helps you read faster, it is not a detection tool. Integrate it into a process, not as a sole alert channel.

Link: llm.datasette.iogithub.com/simonw/llmgithub.com/taketwo/llm-ollama


Stefano Noferi — Founder e CEO/CTO di noze
Tech Entrepreneur — AI Governance & Security Architect

Need support? Under attack? Service Status
Need support? Under attack? Service Status