When a pipeline fails, naoru reads the logs + your PR diff, finds the root cause, and comments the fix right on your pull request.
naoru (直る) is Japanese for "to be fixed / to heal." That's the whole job — your pipeline breaks, naoru tells you why and how to make it right.
❌ build failed 🩺 naoru
─────────────── ─────────
TypeError: Cannot read ──────▶ Root cause: `user` is undefined at src/auth.ts:42
properties of undefined Fix: - if (user.id)
(reading 'id') + if (user?.id)
Confidence: High
- 🔎 Root-cause, not noise — reads the failed job's logs and the PR diff, then explains the actual cause.
- 💬 One sticky comment — updates in place on every re-run. No comment spam.
- 📋 Works without a PR — on
workflow_dispatch/scheduleruns (no PR to comment on), the diagnosis is written to the job Step Summary instead. Great for Terraform deploy/drift pipelines. - 🧠 Any LLM — Anthropic, OpenAI, OpenRouter, xAI (Grok), Groq, or any OpenAI-compatible endpoint.
- 🐳 Runs anywhere — GitHub Action or a portable Docker image for GitLab dind, Jenkins, and local.
- 🛟 Never breaks your build — diagnosis is comment-only and always exits 0.
naoru reads the key from GitHub Actions secrets — never hard-code it in YAML.
Via the GitHub UI:
Your repo → Settings → Secrets and variables → Actions → New repository secret
- Name:
ANTHROPIC_API_KEY(orOPENAI_API_KEY, etc.)- Secret: paste your key
Or via the CLI:
gh secret set ANTHROPIC_API_KEY --repo your-org/your-repo
# paste the key when prompted🔑 Where to get a key: Anthropic · OpenAI · OpenRouter · xAI/Grok · Groq
Drop this into any workflow file (e.g. .github/workflows/ci.yml). It runs only when your build fails:
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: make build # ← your real build/test job
naoru:
needs: [build]
if: ${{ always() && needs.build.result == 'failure' }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # ← post the comment
actions: read # ← read the failed run's logs
steps:
- uses: clouddrove/naoru@v0
with:
api-key: ${{ secrets.ANTHROPIC_API_KEY }} # ← the secret from step 1
provider: anthropic # anthropic | openai | openrouter | xai | groq | customOn the next failing run, naoru posts a 🩺 comment with the root cause and a suggested fix. Done.
⚠️ Thepermissionsblock is required — withoutactions: readnaoru can't fetch logs, and withoutpull-requests: writeit can't comment.
💡 Want naoru to go further?
fix-mode: suggestposts one-click suggestion comments,fix-mode: propens a fix PR — see Auto-fix.
📄 Full examples: examples/usage.yml (per-workflow job) · examples/watcher.yml (one workflow watching all others)
A single comment on the PR, updated in place every run:
Failed job:
buildRoot cause: Type error in
src/auth.ts:42—useris possiblyundefined.Suggested fix:
- if (user.id) + if (user?.id)Confidence: High · react 👍 / 👎
naoru talks to Anthropic natively and to everything else through the OpenAI-compatible API (driven by base-url). Just set provider — override model/base-url when you want.
provider |
default model | endpoint | key secret (example) |
|---|---|---|---|
anthropic |
claude-sonnet-4-6 |
Anthropic SDK | ANTHROPIC_API_KEY |
openai |
gpt-4o |
https://api.openai.com/v1 |
OPENAI_API_KEY |
openrouter |
openai/gpt-4o |
https://openrouter.ai/api/v1 |
OPENROUTER_API_KEY |
xai |
grok-2 |
https://api.x.ai/v1 |
XAI_API_KEY |
groq |
llama-3.3-70b-versatile |
https://api.groq.com/openai/v1 |
GROQ_API_KEY |
custom |
— | set base-url |
any |
# Example: cheap & fast with Groq
- uses: clouddrove/naoru@v0
with:
api-key: ${{ secrets.GROQ_API_KEY }}
provider: groqThe same engine ships as a node:24-alpine image — ghcr.io/clouddrove/naoru — so it runs anywhere, including docker-in-docker runners. It reads the failed-job log from --log-file/stdin and prints the diagnosis. Give it --repo + --pr + GITHUB_TOKEN and it also posts the GitHub PR comment.
# Pipe a failed build log straight into the container
cat build.log | docker run -i \
-e NAORU_API_KEY=$LLM_KEY \
-e NAORU_PROVIDER=anthropic \
ghcr.io/clouddrove/naoru:latestGitLab CI (docker-in-docker)
naoru:
stage: .post
image: ghcr.io/clouddrove/naoru:latest
when: on_failure
variables:
NAORU_PROVIDER: xai
NAORU_MODEL: grok-2
script:
- cat build.log | node /app/dist-cli/index.js
# NAORU_API_KEY set as a masked CI/CD variable (Settings → CI/CD → Variables)CLI env vars / flags
| env | flag | meaning |
|---|---|---|
NAORU_API_KEY |
--api-key |
LLM key |
NAORU_PROVIDER |
--provider |
provider preset (default anthropic) |
NAORU_MODEL |
--model |
model id |
NAORU_BASE_URL |
--base-url |
endpoint override |
NAORU_LOG_FILE |
--log-file |
path to failed-job log (else read stdin) |
NAORU_DIFF_FILE |
--diff-file |
path to diff (optional) |
NAORU_JOB_NAME |
--job-name |
name of the failed job (default pipeline) |
NAORU_MAX_LOG_LINES |
--max-log-lines |
tail N lines of log (default 500) |
GITHUB_TOKEN |
--github-token |
post a comment (optional) |
| — | --repo owner/name |
GitHub repo for comment (optional) |
| — | --pr N |
PR number for comment (optional) |
With no GitHub target, the CLI prints the diagnosis to stdout and exits 0.
Inputs (mirrors action.yml)
| input | required | default | description |
|---|---|---|---|
api-key |
✅ | — | LLM API key (provider-specific). |
provider |
anthropic |
anthropic | openai | openrouter | xai | groq | custom |
|
base-url |
per-provider | Override endpoint. Required when provider: custom. |
|
model |
per-provider | Model id. | |
github-token |
${{ github.token }} |
Token for reading logs and posting comments. | |
max-log-lines |
500 |
Tail this many log lines. | |
failed-job-name |
auto-detect | Explicit failed job name. | |
fix-mode |
off |
off | suggest | pr — see Auto-fix. |
Outputs
| output | description |
|---|---|
root-cause |
Diagnosed root cause. |
confidence |
high | medium | low |
comment-url |
URL of the posted/updated PR comment. |
fix-pr-url |
URL of the auto-opened fix PR (fix-mode: pr only). |
naoru can go beyond diagnosing and act on the fix. Opt in with fix-mode:
- uses: clouddrove/naoru@v0
if: failure()
with:
api-key: ${{ secrets.NAORU_API_KEY }}
fix-mode: suggest # or: pr| mode | what happens | extra permissions |
|---|---|---|
suggest |
Posts one-click GitHub suggestion review comments on the PR, one per hunk. | pull-requests: write |
pr |
Applies the diff on a naoru/fix-<run-id> branch and opens a PR targeting the failing branch (labelled naoru-fix). Never pushes to your branch. |
contents: write, pull-requests: write |
Safety rails, always on:
- Acts only on high-confidence diagnoses that include a diff.
- Never modifies anything under
.github/(CI logs are untrusted input — a fix must not be able to rewrite your workflows). - Caps patches at 300 changed lines; refuses ambiguous or non-matching hunks rather than guessing.
- Skips runs on naoru's own
naoru/fix-*branches, so a failing fix can't loop. - Best-effort: any fix error is a warning, the diagnosis still ships, your pipeline is never blocked.
⚠️ fix-mode: pralso needs the repo setting Settings → Actions → General → "Allow GitHub Actions to create and approve pull requests" enabled, or PR creation fails with "GitHub Actions is not permitted to create or approve pull requests".
🤖 Comments and fix PRs are authored by whatever identity
github-tokencarries — the default token shows asgithub-actions[bot]. To have them authored as naoru, create a GitHub App with that name and pass its installation token asgithub-token.
- Sticky comment — naoru embeds a hidden marker (
<!-- naoru -->) and updates the same comment in place every run, so PRs never fill with duplicate diagnoses. - Cost — each diagnosis is a single LLM call over the tailed logs (
max-log-lines, default 500) plus the PR diff. Want it cheaper? Useprovider: groqoropenaiwithmodel: gpt-4o-mini, and keepmax-log-linesmodest. - Fail-safe — if the LLM call, log fetch, or comment post errors, naoru emits a warning (Action) or stderr line (CLI) and exits 0. A broken diagnostician should never block your pipeline.
Issues and PRs welcome. npm ci && npm test runs the suite; the CI gate also checks the committed dist/ + dist-cli/ bundles are fresh (npm run build && npm run build:cli).
Apache-2.0 © 2026 CloudDrove Inc.