| name | oh-ci |
| description | Diagnose and fix CI failures on a PR, push fixes |
oh-ci
Fix CI failures on a pull request. Work in an isolated worktree, diagnose failures from check run logs, apply fixes, verify, and push.
Invocation
/oh-ci <pr-number>
<pr-number> - the pull request number with failing CI
Prerequisites
- Repo context: Run from the repo root where the PR exists
- GitHub issue PR: The PR should be from an oh-task session (branch
issue/<number>)
Flow
-
Load project background from AGENTS.md, relevant .oh/ artifacts, and RNA MCP context when available.
-
Get PR branch info and create worktree:
ORIGINAL_DIR=$(pwd)
BRANCH=$(gh pr view <pr-number> --json headRefName -q .headRefName)
git fetch origin
git worktree add .worktrees/ci-<pr-number> -B $BRANCH origin/$BRANCH
cd .worktrees/ci-<pr-number>
-
Fetch CI check run details and logs:
HEAD_SHA=$(gh pr view <pr-number> --json headRefName,commits -q '.commits[-1].oid')
gh api repos/{owner}/{repo}/commits/${HEAD_SHA}/check-runs --jq '.check_runs[] | select(.conclusion == "failure") | {name: .name, id: .id, conclusion: .conclusion}'
gh api repos/{owner}/{repo}/check-runs/{check_run_id}/annotations
RUN_ID=$(gh run list --commit "$HEAD_SHA" --status failure --limit 1 --json databaseId --jq '.[0].databaseId')
test -n "$RUN_ID"
gh run view "$RUN_ID" --log-failed
-
Diagnose failures:
- Parse the CI logs to identify the root cause
- Common categories: type errors, test failures, lint violations, build errors
- If multiple failures, identify if they share a root cause
- Read the relevant source files to understand context
-
Fix the code:
- Apply targeted fixes for each failure
- Stage changes (
git add)
- Run the repo-local
/review skill on staged changes
- Handle review findings:
- P1-P3 trivial: fix inline, re-stage
- P1-P3 non-trivial: create GitHub issue as descendant
- P4: discard
-
Verify the fix locally:
pnpm typecheck
pnpm test
pnpm lint
cargo check
cargo test
cargo clippy
Adapt commands to the project's build system. Capture every result and stop before commit or push if any required check fails.
-
Commit fixes:
git commit -m "fix: resolve CI failures on PR #<pr-number>
- <summary of each fix>
Fixes #<descendant-issue> (if any)
[outcome:<name>]"
-
Push:
git push
-
Cleanup worktree:
cd $ORIGINAL_DIR
git worktree remove .worktrees/ci-<pr-number>
-
Exit and report:
- List what CI checks were failing and what was fixed
- Note any remaining issues that need human attention
- Provide PR URL
Descendant Issues
If repo-local review finds non-trivial issues during the fix, create GitHub issues:
PARENT_ISSUE=${BRANCH#issue/}
NEW_ISSUE=$(gh issue create \
--title "Fix: <brief description>" \
--body "Spawned from #${PARENT_ISSUE} during CI fix on PR #<pr-number>.
## Context
<what was found>
## Acceptance
- [ ] Fix applied
- [ ] CI passes" \
--assignee @me | grep -oE '[0-9]+$')
Complete ALL descendant issues before the final push.
Failure Modes
- Flaky tests: If a test failure appears non-deterministic, note it and push anyway. Report as "potentially flaky" in completion.
- Infrastructure failures: If CI failed due to infra (runner OOM, timeout, service outage), report as blocked — no code fix possible.
- Dependency issues: If a transitive dependency broke, attempt version pin or update. If not feasible, report as blocked.
Exit Conditions
- Success: All CI failures diagnosed and fixed, changes pushed
- Blocked: Failure requires human decision or is infrastructure-related
- Error: Cannot diagnose the failure or fix creates worse problems
Completion Signaling (MANDATORY)
CRITICAL: You MUST signal completion when done. Call the signal_completion tool as your FINAL action.
Signal based on outcome:
| Outcome | Call |
|---|
| CI fixed, changes pushed | signal_completion(status: "success", pr: "<pr-url>") |
| Needs human decision | signal_completion(status: "blocked", blocker: "<reason>") |
| Unrecoverable failure | signal_completion(status: "error", error: "<reason>") |
| If you do not signal, the orchestrator will not know you are done and the session becomes orphaned. | |
Fallback: If the signal_completion tool is not available, output your completion status as your final message in the format: COMPLETION: status=<status> pr=<url> or COMPLETION: status=<status> error=<reason>.