Every developer knows this moment.
You push a commit. CI runs. It fails. You open the log and stare at 400 lines of output trying to find the one line that actually matters.
Ten minutes later you're still scrolling.
Why CI logs are so hard to read
CI runners don't write logs for humans. They write them for machines. Everything gets dumped — timestamps, progress bars, ANSI escape codes, dependency install output, test runner boilerplate — and somewhere buried in all of it is the actual error.
The problem isn't that CI is broken. The problem is that the signal is buried under noise.
The most common reasons CI fails
1. A test is failing
Someone changed code that broke an existing test, or a mock is returning the wrong value. The error is in there — you just have to find it.
2. A dependency version conflict
Your CI runner is on a different version of Node, Python, or another runtime than your local machine. Works on your laptop, fails in CI.
3. An environment variable is missing
A secret or config value exists in your local .env but wasn't added to your CI secrets. The app crashes on startup.
4. A timeout
A test or build step is taking too long and CI kills it. The log just says "Process killed" with no explanation.
5. A flaky test
A test that passes 95% of the time but fails randomly due to timing, network, or order-of-execution issues.
The slow way vs the fast way
The slow way is what most developers do — scroll the raw log, Ctrl+F for "error", guess what went wrong, push a fix, wait for CI to run again, repeat.
The fast way is to pipe your log through ci-why:
cat build.log | ci-why
It strips all the noise, sends the relevant parts to Claude, and prints back a plain English explanation:
──────────────────────────────────────────────────
WHY
The authentication service returns null for the token field
instead of a valid string, causing the test assertion to fail.
FAILING LINE
src/services/auth.test.ts:63
SUGGESTED FIX
Check authService.login() in auth.ts — it's returning
{"token": null} for valid credentials.
──────────────────────────────────────────────────
Instead of reading 300 lines, you read 8.
How to set it up
npm install -g ci-why
ci-why setup
The setup wizard walks you through getting a free Anthropic API key and saves it automatically. Takes about 2 minutes.
Then any time a build fails:
# Pipe directly
cat build.log | ci-why
# Or point at a file
ci-why ./logs/build.log
# Get JSON output for scripting
ci-why --json ./build.log
It works with Jest, pytest, Go test, Rust/Cargo, and Maven — auto-detected from your log.
Works in GitHub Actions too
Add it to your workflow and it automatically posts a plain English explanation as a PR comment every time a build fails:
- name: Explain failure with ci-why
if: steps.build.outcome == 'failure'
uses: ciwhy-tool/ci-why@v0.2.0
with:
log-file: /tmp/build.log
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.pull_request.number }}
Every developer on your team sees the explanation — not just the one who installed the tool.
Free and open source
ci-why is completely free. You bring your own Anthropic API key (free to get, costs fractions of a cent per run).
npm install -g ci-why
GitHub: github.com/ciwhy-tool/ci-why
Tags: devops, node, testing, productivity, opensource
Top comments (0)