logsloth reads the failing CI log so I don't have to Anand Biju built logsloth, a command-line tool that parses long failing CI, test, and build logs to surface the single error line, its location, a one-sentence explanation, and a suggested fix. The tool uses plain Python heuristics to find and score evidence lines, then passes only that excerpt to a local gemma3:1b model via Ollama to explain the failure, keeping private logs on the user's machine. Biju said an earlier version that let the model write everything misidentified errors, leading to the split where "code finds the facts, the model only explains them. This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady https://dev.to/challenges/hacktoberfest-week3-2026-10-19 I'm Anand Biju. I built logsloth, a small command line tool for the most boring part of my week: a red CI run. The red X is never the bad part. The bad part is opening the log. You get a few hundred lines of checkout, cache restore, dependency install and cleanup, and somewhere in the middle is the one line that matters. The last line, Process completed with exit code 1 , tells you nothing. So you scroll, you search for "error", you hit forty false matches, and ten minutes later you find out a package was missing. logsloth does that scrolling. Give it a log file, pipe a command into it, or point it at a failed GitHub Actions run: logsloth ci.log npm test 2 &1 | logsloth logsloth --gh https://github.com/owner/repo/actions/runs/1234567890 It prints a short card with four lines. CULPRIT is the real error line. WHERE is the file and line. WHY is one sentence on what went wrong. FIX is the next thing to do. Below that are the handful of log lines it used as evidence, with their original line numbers, so you can check it instead of trusting it. --md prints the same thing as Markdown for a PR comment, and --json is there for scripts. These are all real runs on my machine. The first three use real logs from public projects, pulled with gh run view --log-failed . A ruff-format pre-commit failure in psf/requests. The log is 284 lines and the run ends with about forty lines of git cleanup after the error. logsloth skips that and lands on the hook that failed: A mypy error in pallets/flask. The error message wraps over three lines, and logsloth joins them back together: A failing vitest assertion in vitejs/vite. The log is 653 lines. Here Gemma got distracted by a pnpm store prune line in the excerpt and suggested running it. The validator threw that out, and the card shows the built-in hint instead. The footer says so. And one of the bundled examples, a pytest run where httpx was never installed: A small CLI that reads a long failing CI, test, or build log and tells you the one thing that broke. Code finds the evidence and states the facts. A local open-weight model gemma3:1b via Ollama only explains why it failed and suggests a fix. The model never sees the whole log. When CI goes red you get a few hundred lines of setup, cache restores, and cleanup, with the real error somewhere in the middle. Finding it is boring and you do it many times a week. logsloth does the scrolling for you and runs entirely on your machine, so private logs never leave it. pip install -e . You also need Ollama https://ollama.com and the default model: ollama pull gemma3:1b OLLAMA HOST defaults to http://127.0.0.1:11434 . a log file logsloth path/to/ci.log piped from a local command npm test 2 &1 | logsloth a failed … ollama pull gemma3:1b python3 -m venv .venv && . .venv/bin/activate pip install -e . logsloth examples/pytest httpx.log python -m pytest -q runs 47 tests. They never call the model or the network. The rule I followed: code finds the facts, the model only explains them. My first version let Gemma 3 1B write everything. It went badly. On a cargo error it wrote the literal text "one sentence: what broke" as the culprit. On a jest log it pointed at the test file instead of the file that was missing the import. On the real flask and requests logs it blamed git config and safe.directory , because the cleanup lines at the end of a GitHub log look like errors. That third one is why I stopped testing only on my own example logs. So the work is split. Triage is plain Python. It strips ANSI colours, including the literal ^ 36m that gh run view --log-failed leaves in, plus the timestamps and the job