read-only · air-gap friendly · GitLab + GitHub
Know why your pipeline failed.
A postmortem step that runs only when a pipeline fails. It pulls the failed jobs' logs, works out where and why they broke, and emits a structured report — to the job log, toreport.md/report.json, and optionally as one idempotent note on the merge or pull request.
Thirty seconds to a verdict
On GitHub, the whole setup is one step — it defaults to the run that triggered it:
# GitHub Actions — no install, analyze the run that just failed
- uses: fennet82/ci-doctor@masterThe core idea
Deterministic code decides where the job failed; the LLM only explains why.Phase attribution is a pure function of job metadata and log structure, computed before any model is called — so a loud, non-fatal cache-restore warning can never get blamed over the real exit code 1 in your script. If the classifier is wrong, that is a bug with a failing test, not a prompt to tune.
Never masks the failure
Read-only, and always exits 0 — it cannot change your pipeline's status or hide the real error.
Works with no LLM
Deterministic report out of the box: phase, reason, terminal command, evidence, remediation.
Bring your own model
Any OpenAI-compatible endpoint via api_base — Ollama, vLLM, llama.cpp, an internal gateway.
Air-gapped
No runtime downloads, no telemetry, no hardcoded hosts. Ship as a Docker image or offline wheels.
Two providers, one core
GitLab CI and GitHub Actions are adapters. The classifier never learns a provider's name.
Runs on your laptop
Replay a saved log offline, or point it at a live run — the repo is read from git origin when unset.
Install and try it
# uv (recommended)
uv tool install ci-doctorr
# pip
pip install ci-doctorr
# or the self-contained image, for air-gapped runners
docker run --rm ci-doctor:latest --version# Replay a captured log — no network, no LLM, no CI:
ci-doctor analyze failing-job.log
# Against a live run (reads $CI_PIPELINE_ID / $GITHUB_REPOSITORY in CI):
ci-doctor analyze "$CI_PIPELINE_ID"Get started → walks the whole path: install, a first run on a saved log, and what it needs to reach a live pipeline.