From oss
OSS maintainer fast-close workflow for GitHub PRs. Three phases: (1) PR intelligence — reads the full thread, linked issues, and PR body to synthesize contribution motivation and classify every comment into action items; (2) conflict resolution — checks out the PR branch (fork-aware via gh pr checkout), merges BASE into it, and resolves conflicts semantically using the contributor's intent as the priority lens; (3) implements each action item as a separate attributed commit via Codex, then pushes back to the contributor's fork. Supports three source modes: pr (live GitHub comments only), report (latest /review report findings as action items, no GitHub re-fetch), and pr + report (both sources aggregated and deduplicated in one pass). Also accepts bare comment text for single-comment dispatch.
npx claudepluginhub borda/ai-rig --plugin ossThis skill is limited to using the following tools:
<objective>
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Analyzes competition with Porter's Five Forces, Blue Ocean Strategy, and positioning maps to identify differentiation opportunities and market positioning for startups and pitches.
OSS maintainer fast-close workflow. Given a PR number, three phases fire automatically:
BASE_REF into it, resolve conflicts semantically with the contributor's intent as the priority lensThe result: a conflict-free, review-addressed PR branch pushed to the fork, ready for the maintainer to merge on GitHub — all without touching the GitHub UI.
Core invariant — transparent and reversible: every action produces a visible, named git object (merge commit, fix commit) that can be inspected and reverted individually. This is why all conflict resolution goes forward via git merge (creates a new commit with two parents) and never via git rebase (rewrites SHA history, destroys the ability to revert or cherry-pick individual steps). Each action item becomes its own commit for the same reason — granular revert is always possible.
When given bare comment text, skip straight to Codex dispatch (Step 12).
.temp/output-review-*.md file42) or GitHub PR URL → pr modereport (bare word) → report mode: use latest review report findings as action items; no GitHub re-fetch42 report or <URL> report → pr + report mode: aggregate live GitHub comments + review report findings, deduplicated in one passFoundry plugin check: run
ls ~/.claude/plugins/cache/ 2>/dev/null | grep -q foundry(exit 0 = installed). If the check fails or you are uncertain, proceed as if foundry is available — it is the common case; only fall back if an agent dispatch explicitly fails.
When foundry is not installed, substitute foundry:X references with general-purpose and prepend the role description plus model: <model> to the spawn call:
| foundry agent | Fallback | Model | Role description prefix |
|---|---|---|---|
foundry:sw-engineer | general-purpose | opus | You are a senior Python software engineer. Write production-quality, type-safe code following SOLID principles. |
foundry:qa-specialist | general-purpose | opus | You are a QA specialist. Write deterministic, parametrized pytest tests covering edge cases and regressions. |
foundry:linting-expert | general-purpose | haiku | You are a static analysis specialist. Fix ruff/mypy violations, add missing type annotations, configure pre-commit hooks. |
Skills with --team mode: team spawning with fallback agents still works but produces lower-quality output.
Task hygiene: Before creating tasks, call TaskList. For each found task:
completed if the work is clearly donedeleted if orphaned / no longer relevantin_progress only if genuinely continuing# From plugins/foundry/skills/_shared/preflight-helpers.md — TTL 4 hours, keyed per binary
preflight_ok() {
local f=".claude/state/preflight/$1.ok"
[ -f "$f" ] && [ $(($(date +%s) - $(cat "$f"))) -lt 14400 ]
}
preflight_pass() {
mkdir -p .claude/state/preflight
date +%s >".claude/state/preflight/$1.ok"
}
# codex — optional; intelligence + conflict resolution work without it
CODEX_AVAILABLE=false
if preflight_ok codex; then
CODEX_AVAILABLE=true && echo "codex (openai-codex): ok (cached)"
elif claude plugin list 2>/dev/null | grep -q 'codex@openai-codex'; then # timeout: 15000
preflight_pass codex && CODEX_AVAILABLE=true && echo "codex (openai-codex): ok"
else
echo "codex (openai-codex): missing — action item implementation (Step 8) will be skipped"
fi
# gh binary + auth — required; cached for 4h (auth won't change within a session)
if preflight_ok gh; then
echo "gh: ok (cached)"
elif which gh &>/dev/null && gh auth status &>/dev/null; then
preflight_pass gh && echo "gh: ok ($(gh auth status 2>&1 | grep 'Logged in' | head -1 | xargs))"
elif which gh &>/dev/null; then
echo "Pre-flight failed: gh found but not authenticated — run: gh auth login" && exit 1
else
echo "Pre-flight failed: gh not found — install: brew install gh" && exit 1
fi
# Show current remotes — confirms we are in the right repo and surfaces any existing fork remotes
git remote -v # timeout: 3000
# Sync with remote tracking branch before any git work.
# When local is 1 commit ahead and remote is also 1 commit ahead, git pull merges cleanly.
# This prevents the downstream `git merge --continue --no-edit` from being called out of state.
UPSTREAM=$(git rev-parse --abbrev-ref @{u} 2>/dev/null)
if [ -n "$UPSTREAM" ]; then
git fetch origin 2>/dev/null || true # timeout: 6000
REMOTE_AHEAD=$(git log HEAD..@{u} --oneline 2>/dev/null | wc -l | tr -d ' ')
if [ "$REMOTE_AHEAD" -gt 0 ]; then
echo "Remote is $REMOTE_AHEAD commit(s) ahead — running git pull..."
git pull || {
echo "Pre-flight failed: git pull had conflicts — resolve manually before running /resolve"
exit 1
} # timeout: 6000
echo "✓ git pull: merged"
else
echo "✓ git: up to date"
fi
fi
If gh is missing or not authenticated: stop (error printed above)
If codex is missing: set CODEX_AVAILABLE=false and continue — Steps 3–7 (intelligence + conflict resolution) work without Codex; Step 8 (action items) will be skipped with a notice: ⚠ codex not found — skipping action items. Install: npm install -g @openai/codex
If $ARGUMENTS is empty:
# Find most recent review output (written by /review to .temp/)
REVIEW_FILE=$(ls -t .temp/output-review-*.md 2>/dev/null | head -1)
if [ -z "$REVIEW_FILE" ]; then
echo "No review output found in .temp/ — run /review <PR#> first, or provide a PR number"
exit 1
fi
echo "→ Using: $REVIEW_FILE"
Read $REVIEW_FILE with the Read tool. Extract the PR number from the header line:
## Code Review: PR #<N> or ## Code Review: <N> (where N is a number)grep -oE '(PR #|#)?[0-9]+' "$REVIEW_FILE" | head -1 | grep -oE '[0-9]+'If a PR number is found, set $ARGUMENTS = <extracted number> and proceed in PR mode (Step 2 onwards). Print: → Resolved PR #<N> from review output.
If no PR number is extractable (review was run on a local path, not a PR), print: "Review output does not reference a PR — provide a PR number explicitly: /resolve <PR#>" and exit 1.
Parse $ARGUMENTS:
<number> report or <URL> report (number/URL followed by the word report) → pr + report mode: strip report suffix, set PR# from the remaining token; also find the latest review report using ls -t .temp/output-review-*.md 2>/dev/null | head -1; if no report found print a warning but continue in pr modereport → report mode: find the latest review report using ls -t .temp/output-review-*.md 2>/dev/null | head -1; if no report found stop with: "No review report found in .temp/ — run /review <PR#> first, or provide a PR number"; extract PR# from header if presentTaskCreate(
subject="Resolve PR #<number> — gather action items",
description="Fetch PR thread, linked issues, and/or review report; classify all comments into ACTION_ITEMS",
activeForm="Gathering action items for PR #<number>"
)
Mark it in_progress immediately:
TaskUpdate(task_id=<task_id_from_above>, status="in_progress")
Skip to Step 3b (PR intelligence) when in pr mode or pr + report mode.
When mode == report:
Print before parsing findings:
## Resolve — sources
Mode : report
PR : #<N> (extracted from report header, or "n/a — working on current branch")
GitHub : not fetched
Report : Read <path to report file>
Building action items…
Read the review report file. Parse structured findings from each ### section header (### [blocking] Critical, ### Architecture & Quality, ### Test Coverage Gaps, ### Performance Concerns, ### Documentation Gaps, ### Static Analysis, ### API Design, ### Codex Co-Review). Skip ### OSS Checks, ### Recommended Next Steps, ### Review Confidence, and ### Issue Root Cause Alignment.
Map each finding bullet to the action item schema:
| Severity in report | type |
|---|---|
CRITICAL or [blocking] | [req] |
| HIGH | [req] |
| MEDIUM | [suggest] |
| LOW | [suggest] (omit if total items > 10) |
author: the section owner agent (e.g., foundry:sw-engineer for Architecture, foundry:qa-specialist for Test Coverage)file / line: extract from file:line notation in the finding bullet; leave blank if absentfull_comment_text: the full finding bullet text[report] as a prefix to type (e.g., [report][req], [report][suggest])If PR# was found in the report header (## Code Review: PR #<N> or similar):
$ARGUMENTS = <N> and proceed to Step 4 (checkout); skip Step 3b (PR intelligence) entirelyIf no PR# was found in the header:
Fetch full PR metadata in one call:
gh pr view \
number,title,body,author,labels,isDraft,state, headRefName,baseRefName, headRepositoryOwner,headRepository,isCrossRepository,url, closingIssuesReferences <PR# >--json
Extract and record:
HEAD_REF — source branch name (.headRefName)BASE_REF — target branch name (.baseRefName, e.g. main, develop)PR_AUTHOR — contributor's GitHub login (.author.login)HEAD_REPO_OWNER — owner of the fork/head repository (.headRepositoryOwner.login)BASE_REPO_OWNER — owner of the base repository; extract from .url via split("/")[3] or run gh repo view --json owner -q .owner.login in the project rootIS_FORK — use .isCrossRepository directly (true = fork PR, false = same-repo branch)CLOSING_ISSUES — list of linked issue numbers (.closingIssuesReferences[].number)Fetch the full discussion:
gh pr view <PR# >--comments # PR-level comments + timeline
gh api repos/{owner}/{repo}/pulls/ <PR# >/reviews # formal reviews (Approve / Request Changes)
gh api repos/{owner}/{repo}/pulls/ <PR# >/comments # inline code comments with file + line
If CLOSING_ISSUES is non-empty, fetch each linked issue for motivation context:
gh issue view title,body <issue# >--json
Read the PR title, PR body, linked issue descriptions, and commit messages together. Produce a 2–3 sentence paragraph:
This motivation summary is the priority lens for conflict resolution in Step 7 — it tells you whose logic should win when both sides touched the same area.
Read every comment, review, and inline code comment. Classify each:
| Code | Meaning |
|---|---|
[req] | Change required before merge — requested by a reviewer with write access or the maintainer |
[suggest] | Improvement suggested — nice-to-have, non-blocking |
[question] | Open question that needs an answer before deciding what code to write |
[done] | A subsequent commit or reply already addressed this — skip |
[info] | Praise, acknowledgement, emoji-only — skip |
[self-review] | Finding from the /oss:review report — not a GitHub commenter; author = agent name |
Build ACTION_ITEMS: [{id, type, author, summary, file, line, full_comment_text}]
Print right before the action item table:
## Resolve — sources
Mode : pr
PR : #<N>
GitHub : Read — PR body · <N> comments · <N> reviews · <N> inline code comments
Report : not used
Building action items…
Print the action item table:
### Action Items — PR #<number>
| Type | Author | Status | Summary | File:Line |
|------|--------|--------|---------|-----------|
| [req] | @reviewer | pending | rename param `x` to `count` | src/foo.py:42 |
| [suggest] | @maintainer | pending | add docstring | — |
| [question] | @reviewer | pending | why not use X instead? | — |
Guard: if
[req]items > 15, print the full list and useAskUserQuestionto ask which subset to implement, listing up to 4 grouped options drawn from the items table (mark the first/smallest group as "(Recommended)"), before continuing.
Answer any [question] items that can be resolved from reading the code — if the answer is clear, reclassify to [req] or [suggest]; if it requires maintainer judgement, surface and pause. A question answered by the contributor (not the maintainer) is not automatically closed — if the contributor's answer reveals a known limitation or deferred work (e.g., "currently per-process, Redis is a follow-up"), keep it as [question] and surface it for the maintainer to explicitly accept or reject before proceeding.
Skip when in pr mode.
When mode == pr + report:
Find and read the latest review report (ls -t .temp/output-review-*.md 2>/dev/null | head -1). Parse structured findings using the same logic as Step 3a (report mode) above.
Deduplication:
file:line:
(also flagged by /review)[report] itemRe-prefix GitHub items: once deduplication is complete, add [gh] as a source prefix to all GitHub-sourced items — [req] → [gh][req], [suggest] → [gh][suggest], [question] → [gh][question]. This matches the [report] source prefix and makes source unambiguous in the merged table. This re-prefixing applies only in pr + report mode; single-source pr mode items remain plain [req]/[suggest].
Print right before the merge summary and action item table:
## Resolve — sources
Mode : pr + report
PR : #<N>
GitHub : Read — PR body · <N> comments · <N> reviews · <N> inline code comments
Report : Read <path to report file>
Building action items…
Result: a single merged ACTION_ITEMS list. GitHub-sourced items appear first (maintaining [gh][req]/[gh][suggest] order), followed by surviving [report] items. Print a merge summary before the action item table:
Report merged: <N> findings from /review · <M> deduplicated against GitHub comments · <K> added as [report] items
Mark the Step 2 task completed:
TaskUpdate(task_id=<step2_task_id>, status="completed")
For each item in ACTION_ITEMS create a task:
TaskCreate(
subject="[<type>] <summary> — PR #<number>",
description="Author: @<author> | File: <file:line or '—'> | <full_comment_text>",
activeForm="Implementing: <summary>"
)
<type> — the item's type code: req, suggest, question, done, info, self-review, report-req, report-suggest, etc.<summary> — the item's summary field (truncated to 80 chars if needed)[done] and [info] — no task needed for already-done or praise itemsStore the returned task ID alongside each ACTION_ITEMS entry as task_id.
SAVED_BRANCH=$(git rev-parse --abbrev-ref HEAD) # timeout: 3000
gh pr checkout <PR#> # fetches HEAD_REF; for forks, adds the contributor's remote + sets up tracking # timeout: 15000
gh pr checkout handles forks automatically — it adds a remote named after the contributor's GitHub login and configures tracking. Verify:
git remote -v | grep -v fetch | grep -v push | head -10 # timeout: 3000
git status # confirm we are on HEAD_REF # timeout: 3000
Record FORK_REMOTE: for fork PRs it is the contributor's login (e.g. alice); for same-repo PRs it is origin. The push command in Step 9 is always git push (tracking is configured correctly by gh pr checkout).
# Detect in-progress merge via MERGE_HEAD sentinel — git status --porcelain does not expose this reliably
MERGE_HEAD_FILE="$(git rev-parse --git-dir)/MERGE_HEAD" # timeout: 3000
test -f "$MERGE_HEAD_FILE" && echo "MERGING" || echo "clean"
Case A — MERGING state (MERGE_HEAD present — a previous git merge left markers in the PR branch):
Work directly with the existing markers. Skip to Step 6, substep 6c.
Case B — not MERGING:
Merge BASE_REF into the PR branch (this updates the PR with the latest base changes — the merge direction is BASE → HEAD_REF, not the reverse):
git fetch origin "$BASE_REF" # ensure origin/$BASE_REF is current # timeout: 6000
git merge "origin/$BASE_REF" --no-commit --no-ff # timeout: 6000
Check for conflicted files:
git diff --name-only --diff-filter=U # timeout: 3000
For each conflicted file returned above, create a task before touching any file:
TaskCreate(
subject="Resolve conflict: <filepath> — PR #<number>",
description="Merge conflict in <filepath> from merging origin/<BASE_REF> into <HEAD_REF>. Must be completed before action-item implementation begins.",
activeForm="Resolving conflict: <filepath>"
)
Store the returned task ID alongside each file path as conflict_task_id. Print the conflict task table so it is immediately visible in the task feed:
### Merge Conflicts — PR #<number>
| File | Task | Status |
|------|------|--------|
| src/foo.py | #<task_id> | pending |
| config.yaml | #<task_id> | pending |
Invariant: every conflict task must reach
completed(in Step 7b) before Step 8 begins. Creating them upfront — while the diff is still small — keeps each conflict scoped and independently reversible.
If no conflicts → complete the merge and skip to Step 8:
git merge --continue --no-edit
Report a clean merge, skip Steps 6–7, continue from Step 8.
If more than 20 conflicted files → abort and stop:
git merge --abort
Report the count and file list; use AskUserQuestion to ask whether to continue or re-scope, with options: "Continue (Recommended)" (proceed with all conflicted files), "Re-scope" (abort and narrow the merge target).
Run before touching any conflict markers.
Use the contribution motivation from Step 3b as the primary lens. Additionally:
MERGE_BASE=$(git merge-base "origin/$BASE_REF" "$HEAD_REF") # timeout: 3000
git log $MERGE_BASE..$HEAD_REF --oneline --no-merges # timeout: 3000
git diff $MERGE_BASE $HEAD_REF --stat # timeout: 3000
One-sentence summary: which files/modules this PR owns and what it changes about them.
git log $MERGE_BASE..origin/$BASE_REF --oneline --no-merges # timeout: 3000
SOURCE_LAST_TIME=$(git log "$HEAD_REF" -1 --format="%ci") # timeout: 3000
git log origin/$BASE_REF --after="$SOURCE_LAST_TIME" --oneline # commits the contributor never saw # timeout: 3000
One-sentence summary: what independent changes landed on base after the contributor's last commit — these must be preserved unconditionally.
Delegate per-file conflict edits to foundry:sw-engineer. Build the spawn prompt with all three context sources, then check the result before completing the merge.
Spawn foundry:sw-engineer with this prompt (fill in the bracketed sections from the steps indicated):
Agent(foundry:sw-engineer, prompt="
You are resolving merge conflicts in a checked-out PR branch.
## Conflicted files
<list every file from Step 5 `git diff --name-only --diff-filter=U` output, one per line>
## Contribution motivation (whose intent wins)
<2–3 sentence motivation summary from Step 3b>
## Merge context
### What HEAD_REF added (merge-base log)
<git log $MERGE_BASE..$HEAD_REF --oneline --no-merges output from Step 6a>
### Files changed by this PR (diff stat)
<git diff $MERGE_BASE $HEAD_REF --stat output from Step 6a>
## Instructions
For each conflicted file:
1. Use the Read tool to inspect the full file and locate all conflict markers
2. Determine the correct resolution using the contribution motivation above as the priority lens:
- Contributor's new functionality takes priority for files the PR owns (introduced or substantially rewrote)
- Base's independent refactors and config updates are always preserved
- When both sides changed the same logic, blend: keep the PR's semantic change while incorporating the base's structural update
3. Use the Edit tool to apply targeted replacements that remove all conflict markers and produce the correct resolved content — do NOT rewrite the whole file; use Edit for minimal targeted replacements
4. After resolving each file, stage it with: git add -- <file> (timeout: 3000)
Return ONLY a compact JSON envelope — no prose, no explanation:
{\"status\":\"done\",\"resolved\":N,\"staged\":N,\"confidence\":0.N}
")
Health monitoring: Agent call is synchronous; Claude awaits response natively. If no response within ~15 min, surface partial results with ⏱ and proceed to merge with whatever files were staged.
Parse the JSON envelope returned by sw-engineer. Check that resolved == staged — if they differ, surface the discrepancy before proceeding (a mismatch means at least one file was resolved but not staged, which would leave the merge incomplete).
Complete the merge:
git merge --continue --no-edit # timeout: 3000
Print conflict report:
### Conflict Resolution
| File | Strategy | Notes |
|------|----------|-------|
| src/foo.py | Blended | kept PR's new param, adopted base's renamed import |
| config.yaml | Target | unrelated config change from base, PR had no opinion |
**Result**: N files resolved. Merge commit created.
Mark all conflict tasks completed:
for each (filepath, conflict_task_id) pair from Step 5a: TaskUpdate(task_id=\<conflict_task_id>, status="completed")
If CODEX_AVAILABLE=false: mark all items ⚠ skipped — codex not installed and skip to Step 9.
Conflict gate: before processing any action item, verify every conflict task from Step 5a is
completed. If any conflict task is stillpendingorin_progress, stop — surface the list and wait for the user to resolve before continuing. Action items applied on top of unresolved conflicts compound the diff and make the collision harder to untangle.
Process [req] items first, then [suggest] items. Each item gets its own commit.
Guard: process at most 10 items, then pause and use
AskUserQuestionto ask whether to continue with the remaining items, with options: "Continue (Recommended)" (process next batch of items), "Stop here" (finish report with items processed so far).
For each action item:
# Guard: ensure clean state before each item
test -z "$(git status --porcelain)" || { echo "⚠ dirty tree before item #<id> — stashing"; git stash push -m "resolve-pre-item-<id>"; } # timeout: 3000
# Snapshot before
git diff HEAD --stat # timeout: 3000
Mark the item's task in_progress:
TaskUpdate(task_id=<item.task_id>, status="in_progress")
# Dispatch to Codex
Agent(subagent_type="codex:codex-rescue", prompt="Apply this review feedback to the codebase. Implement exactly what is requested and nothing more. If the change is already present or there is nothing actionable, make no changes and explain why. Feedback from @<author>: <full_comment_text>")
# Check whether code changed
git diff HEAD --stat # timeout: 3000
If code changed → commit:
# Prerequisite: working tree must be clean before Step 7 Codex calls; verify with git diff --stat HEAD before proceeding.
# Stage tracked modifications + new files from Codex (never git add -A)
git add $(git diff HEAD --name-only) # timeout: 3000
git ls-files --others --exclude-standard | grep . | xargs git add -- 2>/dev/null || true # grep . filters empty output (macOS-portable; xargs -r is GNU-only); permission matcher sees 'git ls-files' as first token # timeout: 3000
# timeout: 3000 — git commit (local operation); include co-author trailer per git-commit.md
git commit -m "$(
cat <<'EOF'
<imperative short summary of the change>
[resolve #<item_id>] Review comment by @<author> (PR #<PR_NUMBER>):
"<first 72 chars of full_comment_text>..."
---
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
EOF
)"
If no code changed (already done or non-actionable) → record Codex's reason; do NOT create an empty commit.
Record per-item: committed <SHA> or skipped — <Codex reason>.
Mark the item's task completed:
TaskUpdate(task_id=<item.task_id>, status="completed")
RUN_DIR=".reports/resolve/$(date -u +%Y-%m-%dT%H-%M-%SZ)"
mkdir -p "$RUN_DIR" # timeout: 5000
Spawn both agents in parallel:
Agent(foundry:linting-expert): "Review all files changed in the current branch since origin/<BASE_REF>. List every lint/type violation. Apply inline fixes for any that are auto-fixable. Write your full findings to $RUN_DIR/linting-expert-step9.md using the Write tool, then return ONLY a compact JSON envelope: {fixed: N, remaining: N, files: [...]}."
Agent(foundry:qa-specialist, maxTurns: 15): "Review all files changed in the current branch since origin/<BASE_REF> for correctness, edge cases, and regressions. Flag any blocking issues (bugs, broken contracts, missing test coverage for the changed logic). Write your full findings to $RUN_DIR/qa-specialist-step9.md using the Write tool, then return ONLY a compact JSON envelope: {blocking: N, warnings: N, issues: [...]}."
Health monitoring: Agent calls are synchronous; Claude awaits responses natively. If no response within ~15 min, surface partial results from
$RUN_DIRwith ⏱.
Wait for both. Then:
linting-expert made file changes → commit them:git add $(git diff HEAD --name-only) # timeout: 3000
git commit -m "$(cat <<'EOF'
lint: auto-fix violations after resolve cycle
---
Co-authored-by: Claude Code <noreply@anthropic.com>
EOF
)" # timeout: 3000
foundry:qa-specialist reports blocking issues → fix each one (via Codex if CODEX_AVAILABLE=true, otherwise inline edit), then re-run foundry:qa-specialist once to confirm resolution; if issues remain after one fix pass, surface them in the final report and continue (do not loop indefinitely)Skip this step entirely when in report mode with no PR# (variables $FORK_REMOTE, $HEAD_REF, $BASE_REF were never set — there is no fork branch to push to; the workflow ends at Step 11).
# Ensure fork remote is present (gh pr checkout may not have added it for all setups)
if ! git remote get-url "$FORK_REMOTE" &>/dev/null; then # timeout: 3000
REPO_NAME=$(git remote get-url origin | sed 's|.*/||' | sed 's|\.git$||')
git remote add "$FORK_REMOTE" "https://github.com/$FORK_REMOTE/$REPO_NAME.git" # timeout: 3000
echo "→ Added remote $FORK_REMOTE → https://github.com/$FORK_REMOTE/$REPO_NAME.git"
fi
# Configure tracking if not already set
git branch --set-upstream-to="$FORK_REMOTE/$HEAD_REF" 2>/dev/null || true # timeout: 3000
# Count commits ready to push and announce — user must approve the toolbar permission prompt
PUSH_COUNT=$(git rev-list "$FORK_REMOTE/$HEAD_REF..HEAD" --count 2>/dev/null || git rev-list "origin/$BASE_REF..HEAD" --count) # timeout: 3000
echo "→ $PUSH_COUNT commits ready to push to $FORK_REMOTE/$HEAD_REF — approve the git push request in the toolbar ↑ to complete"
git push # timeout: 30000
# gh pr checkout configured tracking to the fork branch — git push targets it automatically
If push is rejected (fork protection or stale tracking):
git push "$FORK_REMOTE" HEAD:"$HEAD_REF" # timeout: 30000
Verify the push reached GitHub:
gh pr view headRefOid,commits --jq '.commits[-3:] | .[].messageHeadline' <PR# >--json # timeout: 6000
Confirm the latest commit headlines match what was just committed.
Mark any remaining open action item tasks completed. All per-item tasks should already be completed by Step 8; this is a safety close for items skipped (guard paused, question items, codex-not-available).
Then print:
## Resolve Report — PR #<number>
### Contribution
<2–3 sentence motivation summary from Step 3b>
### Conflicts
<conflict table from Step 7, or "No conflicts detected">
### Action Items
| Type | Author | Status | Summary | File:Line |
|------|--------|--------|---------|-----------|
| [req] | @reviewer | ✓ resolved | rename param x → count | src/foo.py:42 |
| [suggest] | @maintainer | ✓ resolved | add docstring | — |
| [question] | @reviewer | ⊘ answered inline — existing approach is correct per linked issue #42 | why not use X? | — |
### Lint + QA
<linting-expert summary: N fixes applied | or "no violations"> / <foundry:qa-specialist summary: N blocking fixed, N warnings | or "clean">
### Push
✓ Pushed to <remote>/<HEAD_REF> — N new commits
**Next**:
- `gh pr merge <PR#> --merge` to merge now (preserves all commits)
## Confidence
**Score**: [0.N]
**Gaps**: [e.g. conflict strategy ambiguity, action items skipped at guard, Codex partial completion]
**Refinements**: N passes. — omit if 0 passes
Read and execute plugins/oss/skills/resolve/modes/comment-dispatch.md.
git pull has conflicts the skill exits with a clear message to resolve manually first — this prevents git merge --continue being called with no in-progress mergegh pr checkout <PR#> always switches to the PR's HEAD branch, never to main/master; all commits land on the PR branch by design. Never push directly to the default branch — if for any reason the PR branch turns out to be the default branch, abort and surface the issue to the usergh pr checkout <PR#> works identically for same-repo branches and forks; for forks it adds the contributor's remote (named after their login) and configures tracking; plain git push then targets the fork branch correctly with no manual remote setuporigin/BASE_REF INTO HEAD_REF (updating the PR branch), NOT the reverse; this preserves the PR branch as the source of truth and keeps the GitHub merge clean; the maintainer still clicks Merge (or runs gh pr merge) after reviewinggit merge; rebase rewrites commit SHAs and breaks cherry-pick / revert; Step 5 uses git merge --continue --no-edit to complete a merge after conflict resolution[req] and [suggest] item must produce exactly one atomic commit; the [resolve #N] tag in the message lets git log --grep='resolve #3' find the exact commit for any action item; this makes the history reviewable, the diff bisectable, and each change independently revertable; an empty commit is never created when Codex makes no changes[question] items — answer inline in the resolve report only (never post to the PR); then reclassify before implementing; never silently implement a response to an unanswered questiongit merge origin/$BASE_REF left markers, the skill skips Steps 5 detection and 6 context-distill, jumps directly to Step 7a (resolve per file), uses the existing markers; no new merge is startedgh pr view --json commits that new commits appear on GitHub before reporting success; exit code 0 from git push is necessary but not sufficient (branch protection rules can silently reject)gh pr merge flags: --merge preserves all commits and history; --squash collapses to one (loses individual action-item commits); never suggest --rebase (rewrites SHAs); default recommendation is --merge unless project convention says otherwisegit merge --abort undoes the entire conflict state and returns the PR branch to pre-merge state; use git push --force-with-lease (never plain --force) as an escape hatch — only when the user explicitly requests it — if push is rejected after local amendingAgent(subagent_type="codex:codex-rescue", ...) calls are background agents subject to CLAUDE.md §8 health monitoring — 15-min hard cutoff, ⏱ marker on timeout; surface partial results via tail -100 on the output file if the agent stallsSessionEnd hook runs git worktree prune — catches any orphaned worktrees from prior sessions<inputs> for full mode definitions, source routing, and action-item derivation per mode.[gh] items (pr + report mode only): commit messages use: [resolve #<id>] @<reviewer> (gh): — same as plain [req]/[suggest] in pr mode, plus the (gh) source annotation.[report] items: commit messages for these items should attribute the finding to the agent, not a GitHub commenter: [resolve #<id>] /review finding by <agent-name> (report: <report-path>): — this distinguishes automated findings from human reviewer requests in git history.foundry:sw-engineer; resolve owns workflow orchestration and context (conflict list, motivation, merge-base log, diff stat); sw-engineer owns code-level semantic resolution (Read → Edit → stage); resolve retains the conflict report block and the git merge --continue call.[question] items left unanswered → record rationale in the resolve report only; do NOT post to the PRCloses #<issue#> or Fixes #<issue#>; if CLOSING_ISSUES were found in Step 3b but the PR body lacks those keywords, add them to the PR description: gh pr edit <PR#> --body "$(gh pr view <PR#> --json body -q .body)\n\nCloses #<issue#>"