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/workflows/ci-doctor.yml
# GitHub Actions — no install, analyze the run that just failed
- uses: fennet82/ci-doctor@master

Full action reference →

The 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.

Where to go next.Concepts  explains the pipeline and what every part of it decides — read it once and the rest stops being a list of unexplained knobs. CI setup  has the drop-in job for GitLab and GitHub, and Reference  is every flag and config key.