Concepts
What the moving parts are called, what each one decides, and where it lives in the code. Read this section once and the configuration reference stops being a list of unexplained knobs.
exit code 1. If the classifier is wrong, that is a bug with a failing test — not a prompt to tune.The shape of the whole thing
Where each module sits, and what actually flows between them. Note the two dotted edges: they are the only ones a model touches, and they carry evidence that has already been selected and redacted.
The same code as layers
Three bands. Providers know their CI system and nothing else; core knows the domain and no provider; outputs render what core decided. The seam through the middle is the only way data crosses.
REST client · log segmenter · failure-reason map
Pure. No network, no clock, and no provider ever named here.
With no model, the deterministic report is the output — not a stub.
grep -ri gitlab ci_doctor/core/must return nothing, and CI fails if it does. That is what makes adding a CI system a matter of dropping in a directory rather than threading a third case through the classifier. The code map walks it file by file.The invariants
These are enforced by tests, not convention. The first three are load-bearing:
- The LLM never selects the failure phase. Attribution is deterministic and auditable.
- No provider identifiers in
core/. Checked by grep in CI. - Always
exit 0. ci-doctor can never change your pipeline's outcome or mask the real failure. - Nothing reaches the public internet by default — no telemetry, no update checks, no runtime downloads.
- Never emit unredacted log content: redaction runs on the prompt and the report.
- Every truncation is visible (
… [N lines elided] …), never a silent cut.