mirror of
https://github.com/stablyai/orca
synced 2026-04-21 14:17:16 +00:00
feat: add auto-pr-merge and auto-submit skills with fast CI polling (#53)
Add auto-pr-merge skill (from noqa) with CI wait times reduced for orca's fast CI: 1-min initial wait + 1-min poll intervals (~6 min max) instead of 8-min + 3-min (~23 min max). Add auto-submit skill to orchestrate the full review-fix-pr-merge pipeline. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dfc01a8903
commit
866272093d
2 changed files with 367 additions and 0 deletions
319
.agents/skills/auto-pr-merge/SKILL.md
Normal file
319
.agents/skills/auto-pr-merge/SKILL.md
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
---
|
||||
name: auto-pr-merge
|
||||
description: Create PR, wait for checks, fix issues iteratively, and merge with --admin
|
||||
---
|
||||
|
||||
# auto-pr-merge
|
||||
|
||||
End-to-end autonomous PR workflow: create PR, wait for CI checks to pass, fix any issues (typecheck, code review), update PR, and merge with admin override. Runs fully autonomously without user confirmation.
|
||||
|
||||
**IMPORTANT**: Execute this entire process autonomously without asking the user for confirmation at any step. Just do it.
|
||||
|
||||
---
|
||||
|
||||
## Process Overview
|
||||
|
||||
```
|
||||
CREATE PR → WAIT FOR CHECKS → FIX LOOP (max 3) → MERGE --admin
|
||||
│ │ │ │
|
||||
/create-pr 1min + 1min polls diagnose CI gh pr merge
|
||||
(up to ~6min) fix issues --admin
|
||||
pn typecheck --squash
|
||||
/review-code --delete-branch
|
||||
commit & push
|
||||
wait for checks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Create PR
|
||||
|
||||
Run the `/create-pr` skill to create or update the pull request.
|
||||
|
||||
```
|
||||
Use the Skill tool: skill: "create-pr"
|
||||
```
|
||||
|
||||
After `/create-pr` completes, extract the PR number and URL:
|
||||
|
||||
```bash
|
||||
gh pr view --json number,url --jq '.number, .url'
|
||||
```
|
||||
|
||||
Store the PR number for later use.
|
||||
|
||||
**CRITICAL: DO NOT STOP after /create-pr completes. Continue to Step 2.**
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Wait for PR Checks
|
||||
|
||||
Use the **Check Polling Procedure** (defined below) to wait for CI checks. Based on the result:
|
||||
|
||||
- `PASSED` → Skip to Step 4 (MERGE)
|
||||
- `FAILED` → Proceed to Step 3 (FIX LOOP)
|
||||
- `NO_CHECKS` → Skip to Step 4 (MERGE) — no CI configured, nothing to wait for
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Fix Loop (Max 3 Iterations)
|
||||
|
||||
Run up to **3 iterations** of the diagnose-fix-review-push cycle.
|
||||
|
||||
### 3a. Diagnose Failures
|
||||
|
||||
Identify which checks failed and get their logs:
|
||||
|
||||
```bash
|
||||
# Get the most recent failed run ID for this branch
|
||||
FAILED_RUN=$(gh run list --branch $(git branch --show-current) --limit 5 --json databaseId,conclusion,name --jq '[.[] | select(.conclusion == "failure")] | .[0].databaseId')
|
||||
echo "Failed run: $FAILED_RUN"
|
||||
|
||||
# View failed step logs (truncated to last 200 lines to avoid context bloat)
|
||||
if [ -n "$FAILED_RUN" ] && [ "$FAILED_RUN" != "null" ]; then
|
||||
gh run view "$FAILED_RUN" --log-failed 2>&1 | tail -200
|
||||
fi
|
||||
```
|
||||
|
||||
If `gh run view --log-failed` returns too much output or doesn't work, fall back to:
|
||||
|
||||
```bash
|
||||
gh run view "$FAILED_RUN" --json jobs --jq '.jobs[] | select(.conclusion == "failure") | {name, steps: [.steps[] | select(.conclusion == "failure") | {name, conclusion}]}'
|
||||
```
|
||||
|
||||
### 3b. Fix Issues
|
||||
|
||||
Based on the failure diagnosis:
|
||||
|
||||
1. **Read the error output** from the failed checks
|
||||
2. **Identify the root cause** (build error, lint error, test failure, type error, etc.)
|
||||
3. **Apply fixes** using the Edit tool
|
||||
4. **Delegate to specialized skills when appropriate**:
|
||||
- **Lint errors**: Run `/fix-lint` skill
|
||||
- **Build errors**: Run `/fix-build` skill
|
||||
- **Test failures**: Read failing test, fix the code or test manually
|
||||
|
||||
### 3c. Run Typecheck
|
||||
|
||||
After applying fixes, verify types are clean:
|
||||
|
||||
```bash
|
||||
pn typecheck 2>&1
|
||||
```
|
||||
|
||||
- If typecheck passes: continue to 3d
|
||||
- If typecheck fails: fix type errors and re-run (up to 3 attempts within this step)
|
||||
- Read the error output
|
||||
- Fix the type errors
|
||||
- Re-run `pn typecheck`
|
||||
- If still failing after 3 attempts: move on to 3d anyway (CI will catch remaining issues)
|
||||
|
||||
### 3d. Run Code Review (Quick Round)
|
||||
|
||||
Run **only** `/review-code` to catch any issues introduced by the fixes. Do NOT run `/review-correctness`, `/review-via-codex`, `/review-algorithm-architecture`, or any other review skill — only `/review-code`:
|
||||
|
||||
```
|
||||
Use the Skill tool: skill: "review-code"
|
||||
```
|
||||
|
||||
After review completes:
|
||||
- If **Critical or High** issues found: fix them using the Edit tool, then re-run `pn typecheck` to verify the review fixes don't introduce type errors
|
||||
- If only **Medium or Low** issues: acceptable, continue
|
||||
- If **no issues**: continue
|
||||
|
||||
### 3e. Update PR
|
||||
|
||||
Commit and push only if there are actual changes:
|
||||
|
||||
```bash
|
||||
# Check if there are changes to commit
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
git add -A && git commit -m "fix: address CI failures and review feedback"
|
||||
git push --force-with-lease
|
||||
else
|
||||
echo "NO_CHANGES"
|
||||
fi
|
||||
```
|
||||
|
||||
- If `NO_CHANGES`: No fixes were needed/possible. Exit the fix loop and proceed to Step 4.
|
||||
- If changes were pushed: continue to 3f.
|
||||
|
||||
### 3f. Wait for PR Checks Again
|
||||
|
||||
Use the **Check Polling Procedure** (defined below) to wait for CI checks. Based on the result:
|
||||
|
||||
- `PASSED` → Exit fix loop, proceed to Step 4
|
||||
- `FAILED` → Next iteration of fix loop (back to 3a)
|
||||
- `NO_CHECKS` → Exit fix loop, proceed to Step 4
|
||||
|
||||
If max 3 fix iterations reached, proceed to Step 4 anyway.
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Merge with --admin
|
||||
|
||||
Merge the PR using admin override with squash merge.
|
||||
|
||||
**IMPORTANT: Worktree detection.** When running from a git worktree, `--delete-branch` will fail because `gh` tries to checkout the default branch locally, but it's already checked out in the main worktree. Detect this and handle accordingly:
|
||||
|
||||
```bash
|
||||
# Check if we're in a worktree (not the main working tree)
|
||||
IS_WORKTREE=false
|
||||
if [ "$(git rev-parse --git-dir)" != "$(git rev-parse --git-common-dir)" ]; then
|
||||
IS_WORKTREE=true
|
||||
fi
|
||||
|
||||
BRANCH=$(git branch --show-current)
|
||||
|
||||
if [ "$IS_WORKTREE" = "true" ]; then
|
||||
# In a worktree: merge WITHOUT --delete-branch, then delete remote branch separately
|
||||
gh pr merge --admin --squash
|
||||
# Delete the remote branch manually (local cleanup happens when worktree is removed)
|
||||
git push origin --delete "$BRANCH" 2>/dev/null || true
|
||||
else
|
||||
# Normal repo: use --delete-branch as usual
|
||||
gh pr merge --admin --squash --delete-branch
|
||||
fi
|
||||
```
|
||||
|
||||
- `--admin` bypasses branch protection rules (required reviews, status checks)
|
||||
- `--squash` squashes all commits into one clean commit
|
||||
- `--delete-branch` cleans up the feature branch after merge (skipped in worktrees to avoid checkout conflict)
|
||||
|
||||
If merge fails:
|
||||
1. Check the error message
|
||||
2. If the error contains `'master' is already used by worktree` or similar: retry without `--delete-branch` and delete the remote branch manually with `git push origin --delete <branch>`
|
||||
3. If merge conflicts: use Skill tool with `skill: "resolve-conflicts"`, push, then retry merge once
|
||||
4. If other error: report the full error to the user
|
||||
|
||||
---
|
||||
|
||||
## Check Polling Procedure
|
||||
|
||||
This is the shared polling logic used by Step 2 and Step 3f. **Do NOT run this as a single long bash command** — the Bash tool will timeout. Instead, run each poll as a **separate Bash call**.
|
||||
|
||||
**IMPORTANT: Minimize token waste.** Do NOT add verbose commentary between polls. Just run the wait, run the check, and act on the result. No cheerful status messages, no "patience is key", no filler text.
|
||||
|
||||
### Initial wait
|
||||
|
||||
After a push, CI takes time to run. Wait **1 minute** before the first poll:
|
||||
|
||||
```bash
|
||||
echo "Waiting 1 minute for CI checks to run..." && sleep 60
|
||||
```
|
||||
|
||||
**IMPORTANT**: You MUST actually execute the `sleep 60` command and wait for it to complete. Do NOT skip the sleep or claim you waited without running the command. The sleep ensures CI has time to finish.
|
||||
|
||||
**CRITICAL**: When calling the Bash tool for `sleep 60`, you MUST set `timeout: 120000` (2 minutes) on the Bash tool call. Similarly, for `sleep 60` poll interval calls, set `timeout: 120000` (2 minutes).
|
||||
|
||||
### Poll loop (run each poll as a separate Bash call)
|
||||
|
||||
For each poll attempt (1 through 5):
|
||||
|
||||
```bash
|
||||
CHECKS=$(gh pr checks --json name,state,bucket 2>&1)
|
||||
echo "$CHECKS"
|
||||
|
||||
# Parse results using 'bucket' field (pass, fail, pending, skipping, cancel)
|
||||
if echo "$CHECKS" | jq -e 'length == 0' >/dev/null 2>&1; then
|
||||
echo "RESULT:NO_CHECKS"
|
||||
elif echo "$CHECKS" | jq -e '[.[].bucket] | all(. == "pass" or . == "skipping")' >/dev/null 2>&1; then
|
||||
echo "RESULT:PASSED"
|
||||
elif echo "$CHECKS" | jq -e '[.[].bucket] | any(. == "fail" or . == "cancel")' >/dev/null 2>&1; then
|
||||
echo "RESULT:FAILED"
|
||||
else
|
||||
echo "RESULT:PENDING"
|
||||
fi
|
||||
```
|
||||
|
||||
### Decision logic after each poll
|
||||
|
||||
- `RESULT:PASSED` → Return `PASSED`. Stop polling.
|
||||
- `RESULT:FAILED` → Return `FAILED`. Stop polling.
|
||||
- `RESULT:PENDING` → Wait **1 minute**, then poll again (use `timeout: 120000` on the Bash tool call):
|
||||
```bash
|
||||
sleep 60
|
||||
```
|
||||
- `RESULT:NO_CHECKS` → Return `NO_CHECKS` (no CI configured).
|
||||
|
||||
### After 5 polls (timeout)
|
||||
|
||||
If checks are still pending after 5 polls (~6 min total), return `FAILED` to enter the fix loop for investigation.
|
||||
|
||||
### Handling stale checks after re-push (Step 3f only)
|
||||
|
||||
After pushing new commits in Step 3e, old check results may linger briefly. To avoid reading stale results:
|
||||
|
||||
1. Record the latest commit SHA **before pushing**: `OLD_SHA=$(git rev-parse HEAD)`
|
||||
2. After pushing, the first 1-2 polls should verify the check suite is for the **new** commit. If `gh pr checks` still shows the old results (check names match but they completed instantly), wait an extra 30s.
|
||||
3. Alternatively, look for checks with `state: "IN_PROGRESS"` or `"QUEUED"` as a signal that fresh checks have started.
|
||||
|
||||
---
|
||||
|
||||
## Exit Conditions
|
||||
|
||||
- **Success**: PR merged successfully
|
||||
- **Max fix iterations**: After 3 fix loop iterations, attempt merge with --admin regardless
|
||||
- **No changes to fix**: Fix loop produced no changes, merge with --admin
|
||||
- **No CI checks**: Repo has no checks configured, merge immediately
|
||||
- **Unrecoverable error**: PR creation fails, merge fails after retry, or gh CLI issues
|
||||
|
||||
---
|
||||
|
||||
## Progress Tracking
|
||||
|
||||
Display progress after each major step:
|
||||
|
||||
```
|
||||
╔════════════════════════════════════════════════════════════╗
|
||||
║ AUTO PR MERGE ║
|
||||
╠════════════════════════════════════════════════════════════╣
|
||||
║ Step 1 - Create PR: ✅ PR #123 created ║
|
||||
║ Step 2 - Wait for checks: ❌ 2/5 checks failed ║
|
||||
║ Step 3 - Fix Loop: ║
|
||||
║ Iteration 1/3: ║
|
||||
║ Diagnose: ✅ Type errors in 2 files ║
|
||||
║ Fix: ✅ Fixed type errors ║
|
||||
║ Typecheck: ✅ Passed ║
|
||||
║ Review: ✅ No critical issues ║
|
||||
║ Push: ✅ Updated PR ║
|
||||
║ Checks: ✅ All passed ║
|
||||
║ Step 4 - Merge: ✅ Merged with --admin --squash ║
|
||||
╠════════════════════════════════════════════════════════════╣
|
||||
║ PR URL: https://github.com/org/repo/pull/123 ║
|
||||
║ Result: Successfully merged! ║
|
||||
╚════════════════════════════════════════════════════════════╝
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Critical Instructions
|
||||
|
||||
1. **DO NOT ask for user confirmation** - Execute the entire workflow autonomously
|
||||
2. **DO NOT stop after /create-pr** - The PR creation is just step 1 of 4
|
||||
3. **DO NOT stop after checks pass** - Must complete the merge step
|
||||
4. **DO NOT run polling as a single long bash loop** - Each poll must be a separate Bash call to avoid the 2-minute Bash timeout. Use `sleep` in its own Bash call between polls.
|
||||
5. **DO wait the full polling period** - Don't skip check waiting; CI needs time
|
||||
6. **DO run typecheck before review** - Catch type errors early
|
||||
7. **DO run /review-code in each fix iteration** - Ensure code quality
|
||||
8. **DO check for actual changes before committing** - Skip commit/push if `git status --porcelain` is empty
|
||||
9. **DO use --admin for merge** - This is intentional to bypass protection rules
|
||||
10. **DO use --squash for merge** - Keep git history clean
|
||||
11. **DO delete branch after merge** - Clean up with --delete-branch
|
||||
12. **Maximum 3 fix iterations** - Don't loop forever; after 3, merge with --admin
|
||||
13. **DO NOT run /review-correctness or /review-via-codex** - This skill only uses `/review-code` for quick checks in the fix loop. Codex-based reviews are slow and belong in `/auto-review-fix`, not here.
|
||||
14. **DO actually execute sleep commands** - When the skill says `sleep 60`, you MUST run the bash command and wait for it to complete. Do not skip or fabricate the wait.
|
||||
15. **DO set timeout on Bash tool for sleep commands** - `sleep 60` requires `timeout: 120000`. The default 2-minute Bash timeout is sufficient for 1-minute sleeps but set it explicitly for safety.
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If `/create-pr` fails: Report error and exit
|
||||
- If `gh` CLI is not installed or authenticated: Report and exit
|
||||
- If no CI checks are configured: Skip waiting and merge directly
|
||||
- If check polling times out: Enter fix loop to investigate
|
||||
- If typecheck loops more than 3 times within a single fix iteration: Move on to review
|
||||
- If fix loop produces no changes: Exit loop and merge with --admin
|
||||
- If merge fails due to conflicts: Try `/resolve-conflicts`, push, then retry merge once
|
||||
- If merge fails for other reasons: Report the error to the user with the full error output
|
||||
48
.agents/skills/auto-submit/SKILL.md
Normal file
48
.agents/skills/auto-submit/SKILL.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
name: auto-submit
|
||||
description: End-to-end autonomous pipeline that runs auto-review-fix, then auto-pr-merge
|
||||
---
|
||||
|
||||
# auto-submit
|
||||
|
||||
Autonomous pipeline: review+fix code, then create PR and merge. **Execute without user confirmation.**
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Auto Review-Fix
|
||||
|
||||
**IMPORTANT**: Run auto-review-fix as a sub-agent (not an inline skill) to ensure it gets its own isolated context window. This prevents instruction dilution and ensures fix phases properly spawn their own Task() sub-agents as required.
|
||||
|
||||
```
|
||||
Agent(
|
||||
subagent_type: "general-purpose",
|
||||
description: "Run auto-review-fix",
|
||||
prompt: "Run the /auto-review-fix skill. Follow ALL instructions exactly, especially: all fixes MUST be done via Task() subagents with opus-4-5. No direct edits."
|
||||
)
|
||||
```
|
||||
|
||||
Wait for the agent to complete. Then commit any changes:
|
||||
|
||||
```bash
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
git add -A && git commit -m "fix: address auto-review findings"
|
||||
fi
|
||||
```
|
||||
|
||||
**Continue to Step 2 — do not stop here.**
|
||||
|
||||
### 2. Auto PR-Merge
|
||||
|
||||
```
|
||||
Use the Skill tool: skill: "auto-pr-merge"
|
||||
```
|
||||
|
||||
Handles PR creation, CI polling, fix loops, and merge with `--admin --squash`.
|
||||
|
||||
## Rules
|
||||
|
||||
- Execute autonomously — no user confirmation
|
||||
- Both steps run sequentially — do not stop between them
|
||||
- Commit changes between steps
|
||||
- If Step 1 fails catastrophically, stop (don't create a broken PR)
|
||||
- If Step 2 fails, report the error with PR URL if available
|
||||
Loading…
Reference in a new issue