pr-greenlight
SkillMonitoring & opsAgent Loop that runs local pre-flight CI checks, auto-fixes issues, creates/pushes the PR, monitors CI, and loops until all checks pass. Replaces the manual chain of preflight → create-pr → babysit-pr.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the pr-greenlight skill
What this skill tells your AI
The instructions your AI receives, as published by uniclipboard/uniclipboard in .agents/skills/pr-greenlight/SKILL.md and read by ahel’s review.
Purpose
A single Agent Loop that takes uncommitted or committed work on a feature branch all the way to a green PR. It replaces the manual chain of:
- (forgotten) local checks → push → CI fails → new session to fix → repeat
$create-pr→ wait →$babysit-pr→ wait → fix → push → wait
The loop runs: Pre-flight → Auto-fix → Push/PR → Monitor CI → Fix CI → Loop until green.
When to trigger
$pr-greenlight- full loop: preflight + create PR + monitor$pr-greenlight preflight- only run local pre-flight checks, no push- User says "帮我把这个 PR 搞绿", "run preflight", "pre-flight checks", "搞定 PR"
State file
/tmp/codex-pr-greenlight-state.json:
{
"phase": "preflight|pushed|monitoring",
"pr_number": null,
"round": 0,
"max_rounds": 4,
"preflight_passed": false,
"checks_run": [],
"fixes_applied": [],
"processed_comment_ids": [],
"started_at": "ISO timestamp"
}
Lock file: /tmp/codex-pr-greenlight.lock
Phase 1 — Perceive: Analyze what changed
touch /tmp/codex-pr-greenlight.lock
Run in parallel:
git rev-parse --abbrev-ref HEAD
git status --short
git diff main...HEAD --stat
git diff main...HEAD --name-only
git log main..HEAD --format="%h %s"
From the file list, classify what changed into categories:
| Category | Detection pattern |
|---|---|
rust | *.rs, Cargo.toml, Cargo.lock |
frontend | src/**/*.{ts,tsx,js,jsx,css}, package.json, bun.lockb |
api-endpoints | *.rs files containing #[utoipa::path] or #[tauri::command] changes |
tauri-ipc | changes in src-tauri/src/, DTO structs used by Tauri commands |
openapi | schema/openapi.json, files with #[utoipa::path] |
docs-site | docs-site/** |
markdown | *.md (outside docs-site) |
generated | src/api/generated/**, src/lib/ipc-bindings.generated.ts |
Store the categories in state as change_categories.
Refuse conditions (same as create-pr):
- On
main→ refuse git log main..HEADempty → refuse (nothing to PR)gh auth statusfails → ask user to auth
Phase 2 — Reason & Act: Pre-flight checks
Run ONLY the checks relevant to change_categories. Each check follows: run → detect failure → auto-fix → re-run → confirm.
2a — Format (always run)
# Rust format (if rust changed)
cargo fmt --all --check 2>&1
# If fails:
cargo fmt --all
git add -u '*.rs'
# Frontend format (if frontend/markdown/docs changed)
bun run format 2>&1
# Prettier auto-fixes; stage changed files
git add -u
2b — Code generation drift (the #1 CI failure cause)
Only if rust or api-endpoints changed:
# 1. OpenAPI schema
bun run gen:openapi 2>&1
git diff --exit-code schema/openapi.json
# If diff: stage it
git add schema/openapi.json
# 2. IPC bindings (if tauri-ipc changed)
cargo test -p uc-tauri --test specta_export 2>&1
git diff --exit-code src/lib/ipc-bindings.generated.ts
# If diff: stage it
git add src/lib/ipc-bindings.generated.ts
# 3. API client (if openapi.json changed in step 1 or was already changed)
bun run gen:client 2>&1
git diff --exit-code src/api/generated/
# If diff: stage it
git add src/api/generated/
2c — Lint (scoped to changed files)
# Frontend lint — scope to changed files only (full repo has baseline debt)
CHANGED_TS=$(git diff main...HEAD --name-only --diff-filter=d -- '*.ts' '*.tsx' '*.js' '*.jsx' | head -50)
if [ -n "$CHANGED_TS" ]; then
bun run lint --fix -- $CHANGED_TS 2>&1
git add -u
fi
2d — Compilation & type check
# Rust check (if rust changed)
cargo check --workspace --locked 2>&1 | tail -40
# Frontend build = tsc + vite (if frontend changed)
bun run build 2>&1 | tail -40
If either fails, do NOT auto-fix — these are real errors. Report to user with the error output and ask how to proceed.
2e — Tests (if relevant code changed)
# Frontend tests (if frontend changed)
bun run test -- --run 2>&1 | tail -40
# Rust tests are slow — only run focused tests for changed crates
# Detect changed crates from file paths
CHANGED_CRATES=$(git diff main...HEAD --name-only -- 'crates/*/src' 'apps/*/src' | sed 's|.*/\(crates/[^/]*\)/.*|\1|;s|.*/\(apps/[^/]*\)/.*|\1|' | sort -u)
for crate_path in $CHANGED_CRATES; do
crate_name=$(basename $crate_path)
cargo test -p $crate_name --lib 2>&1 | tail -20
done
2f — Markdown lint-staged simulation (if markdown changed)
# Only for non-docs-site markdown
CHANGED_MD=$(git diff main...HEAD --name-only --diff-filter=d -- '*.md' ':!docs-site/**' | head -20)
if [ -n "$CHANGED_MD" ]; then
for f in $CHANGED_MD; do
node scripts/fix-md-cjk-emphasis.mjs "$f" 2>/dev/null
npx autocorrect --fix "$f" 2>/dev/null
npx prettier --write "$f" 2>/dev/null
done
git add -u '*.md'
fi
2g — Commit pre-flight fixes
If any files were staged by auto-fix steps:
git diff --cached --stat
If there are staged changes, commit them:
git commit -m "$(cat <<'EOF'
chore: pre-flight auto-fix (format, codegen, lint)
EOF
)"
Update state: preflight_passed = true.
Pre-flight summary
Print a table:
Pre-flight results:
✓ cargo fmt
✓ prettier
✓ OpenAPI schema (regenerated, +12 -3)
✓ IPC bindings (no drift)
✓ API client (regenerated)
✓ ESLint (2 auto-fixed)
✓ cargo check
✓ tsc + vite build
✓ vitest (14 passed)
✓ cargo test uc-core (23 passed)
— cargo test uc-daemon (skipped, no changes)
If the user only asked for $pr-greenlight preflight, stop here. Clean up the lock file and report results.
Phase 3 — Push & Create PR
If pre-flight passed, proceed to push and create PR.
Delegate to the create-pr skill logic:
- Branch name review (propose rename if needed)
- docs-site impact scan
- Push and
gh pr create
Key points:
- Follow all
create-prconventions (title format, body format, branch name check) - Record the PR number in state
After PR is created, immediately proceed to Phase 4.
Phase 4 — Monitor CI (Agent Loop)
This is the core monitoring loop, similar to babysit-pr but integrated.
4a — Wait for CI to start
# Give CI 30s to register checks
sleep 30
gh pr checks --json name,state,conclusion 2>/dev/null
If no checks have registered, keep the current turn active, wait with the available command/session wait mechanism, and check again. Do not end the task merely because CI has not appeared yet.
4b — Check status
gh pr checks --json name,state,conclusion,link 2>/dev/null
Classify:
- All passed → go to 4c (check for review comments before declaring victory)
- Some pending -> continue monitoring in the same turn
- Some failed → proceed to 4d
4c — Check for bot review comments
Same as babysit-pr Step 2b — check all three GitHub comment endpoints:
BOT_FILTER='select(.user.login | test("coderabbitai|github-actions|codecov"))'
# Inline review comments
gh api repos/UniClipboard/UniClipboard/pulls/<PR>/comments \
--jq "[.[] | ${BOT_FILTER} | {id, user: .user.login, body, path, line}]"
# Review bodies
gh api repos/UniClipboard/UniClipboard/pulls/<PR>/reviews \
--jq "[.[] | ${BOT_FILTER} | {id, user: .user.login, body, state}]"
# Issue comments (CodeRabbit walkthrough lives here)
gh api repos/UniClipboard/UniClipboard/issues/<PR>/comments \
--jq "[.[] | ${BOT_FILTER} | {id, user: .user.login, body: (.body | .[0:2000])}]"
Filter out processed_comment_ids. If zero unprocessed actionable comments AND all checks pass → Success. Clean up.
4d — Fix failures
For each failed check or new review comment:
- Diagnose: Fetch logs (
gh run view <run_id> --log-failed | tail -100), read relevant code - Classify:
- Format/lint failure → auto-fix (same as pre-flight 2a-2c)
- Code generation drift → re-run gen commands (same as 2b)
- Compilation error → fix the code
- Test failure → fix the code
- CodeRabbit comment → evaluate: must-fix (correctness/security) vs nit (skip)
- Fix: Edit files surgically
- Validate locally: Run the same check that failed to confirm fix works
- Commit and push:
git add <specific files>
git commit -m "$(cat <<'EOF'
fix: address CI feedback (pr-greenlight round N)
EOF
)"
git push
Increment round in state. If round >= max_rounds → clean up with warning.
4e - Loop back
After pushing a fix, prefer gh pr checks --watch --interval 30 and poll its command session in bounded intervals. Re-enter at Phase 4b when the checks finish. Keep the current Codex turn alive and continue reporting useful status while waiting.
Cleanup
On success:
rm -f /tmp/codex-pr-greenlight.lock /tmp/codex-pr-greenlight-state.json
✅ PR #<N> is green. All CI checks passed after <round> round(s).
URL: <pr_url>
Pre-flight caught: <list of issues auto-fixed before push>
CI rounds: <N>
On max rounds (4):
rm -f /tmp/codex-pr-greenlight.lock /tmp/codex-pr-greenlight-state.json
⚠️ PR #<N> still has failures after 4 rounds. Manual review needed.
Remaining failures: <list>
URL: <pr_url>
On timeout (90 min):
rm -f /tmp/codex-pr-greenlight.lock /tmp/codex-pr-greenlight-state.json
Safety guardrails
- Max 4 rounds of CI fix cycles (round only increments on push)
- 90-minute hard timeout
- Lock file prevents re-entrant triggering
- Never
--forcepush - Never amend existing commits
- If a fix breaks something else (cargo check / tsc fails after edit), revert the fix and report
- Skip CodeRabbit style nits — only fix correctness/security/performance issues
- Pre-flight auto-fixes go in a dedicated commit, not mixed with feature work
- Scoped lint: only lint changed files (repo has baseline ESLint debt)
processed_comment_idsprevents duplicate processing
Interaction with existing skills
- Supersedes manual
$create-pr+$babysit-prchain for the common case $create-prand$babysit-prremain available for standalone use- If a PR already exists for the branch, skip Phase 3 (push only, no
gh pr create) - If the user invokes
$pr-greenlight preflight, only Phase 1-2 execute (no push, no PR)
Anti-patterns
- Running all checks regardless of what changed (wastes time on unrelated failures)
- Auto-fixing compilation errors without understanding them
- Pushing broken code because "CI will catch it"
- Running
bun run linton entire repo (33 baseline errors will confuse the loop) - Treating
cargo fmtfailures as real bugs (they're always auto-fixable) - Skipping the local validation step after fixing a CI failure (leads to ping-pong)
- Processing old/already-addressed CodeRabbit comments
- Applying every CodeRabbit nit blindly
Signals
- GitHub stars
- 2k
- Forks
- 76
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
pr-greenlight- Source
- github.com/uniclipboard/uniclipboard