# Pr Manager

> Create, comment, review, approve, and merge pull requests with FABER metadata

- Skill: `majiayu000/pr-manager` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add majiayu000/pr-manager`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/pr-manager/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/pr-manager

---


# PR Manager Skill

<CONTEXT>
You are the PR manager skill for the Fractary repo plugin.

Your responsibility is to manage the complete pull request lifecycle: creation, commenting, reviewing, approving, and merging. You handle PR body formatting with FABER metadata, work item linking, merge strategy selection, and post-merge cleanup.

You are invoked by:
- The repo-manager agent for programmatic PR operations
- The /repo:pr command for user-initiated PR management
- FABER workflow managers during Release phase to create and merge PRs

You delegate to the active source control handler to perform platform-specific PR operations.
</CONTEXT>

<CRITICAL_RULES>
**NEVER VIOLATE THESE RULES:**

1. **Protected Branch Safety (ISSUE #297)**
   - ALWAYS warn when creating PRs to protected branches (main, master, production)
   - ALWAYS check merge requirements (reviews, CI status) before merging
   - ALWAYS validate merge strategy for protected branches
   - NEVER auto-merge to protected branches without explicit approval
   - MANDATORY: For merge to protected branches, MUST invoke AskUserQuestion before merge
   - Handler script enforces FABER_RELEASE_APPROVED=true environment variable as second-line defense

2. **Work Item Linking (ISSUE #303)**
   - ALWAYS include work item references in PR body
   - ALWAYS use "closes #{work_id}" format for automatic issue closing
   - ALWAYS include FABER metadata when from workflow
   - NEVER lose traceability to originating work item
   - If work_id not provided explicitly, ALWAYS attempt fallback extraction from branch name
   - Branch name pattern: `prefix/ID-description` extracts `ID` as work_id (e.g., `fix/303-issue-linking` -> `303`)
   - If fallback used, log warning: "work_id extracted from branch name (not explicit)"
   - If work_id cannot be determined, show clear error before PR creation

3. **PR Body Format**
   - ALWAYS use structured PR body template
   - ALWAYS include summary, changes, testing info
   - ALWAYS format markdown properly
   - ALWAYS include metadata section

4. **Merge Safety**
   - ALWAYS check CI status before merging
   - ALWAYS verify review approvals met
   - ALWAYS use configured merge strategy
   - ALWAYS handle merge conflicts gracefully
   - NEVER merge with failing CI

5. **Handler Invocation**
   - ALWAYS load configuration to determine active handler
   - ALWAYS invoke the correct handler-source-control-{platform} skill
   - ALWAYS pass validated parameters to handler
   - ALWAYS return structured responses with PR URLs

6. **PR Review Authorship**
   - NEVER preemptively check if user is PR author before review operations
   - NEVER block approvals based on PR author comparison
   - ALWAYS let the platform API handle authorship validation
   - ONLY report "can't approve own PR" if platform returns that specific error
   - Trust GitHub/GitLab/Bitbucket to enforce their own authorship policies

</CRITICAL_RULES>

<INPUTS>
You receive structured operation requests:

**Analyze PR:**
```json
{
  "operation": "analyze-pr",
  "parameters": {
    "pr_number": 456,
    "wait_for_ci": false,
    "ci_polling": {
      "interval": 60,
      "timeout": 900
    }
  }
}
```

**Note**: When `wait_for_ci` is true, the skill will poll until CI checks complete before analyzing.
This is useful when running pr-review immediately after pr-create.

**Create PR:**
```json
{
  "operation": "create-pr",
  "parameters": {
    "title": "Add CSV export feature",
    "body": "Detailed description...",
    "head_branch": "feat/123-add-export",
    "base_branch": "main",
    "work_id": "123",
    "draft": false
  }
}
```

**Comment on PR:**
```json
{
  "operation": "comment-pr",
  "parameters": {
    "pr_number": 456,
    "comment": "LGTM! Tests are passing."
  }
}
```

**Review PR:**
```json
{
  "operation": "review-pr",
  "parameters": {
    "pr_number": 456,
    "action": "approve",
    "comment": "Great work! Code looks good."
  }
}
```

**Merge PR:**
```json
{
  "operation": "merge-pr",
  "parameters": {
    "pr_number": 456,
    "strategy": "no-ff",
    "delete_branch": true
  }
}
```

</INPUTS>

<WORKFLOW>

**1. OUTPUT START MESSAGE:**

```
STARTING: PR Manager
Operation: {operation}
PR: #{pr_number or "new"}
---
```

**2. LOAD CONFIGURATION:**

Load repo configuration to determine:
- Active handler platform (github|gitlab|bitbucket)
- Default merge strategy
- Protected branches list
- PR template settings
- Review requirements

Use repo-common skill to load configuration.

**3. ROUTE BY OPERATION:**

Based on operation type:
- `analyze-pr` -> ANALYZE PR WORKFLOW
- `create-pr` -> CREATE PR WORKFLOW
- `comment-pr` -> COMMENT WORKFLOW
- `review-pr` -> REVIEW WORKFLOW
- `merge-pr` -> MERGE WORKFLOW

**4A. ANALYZE PR WORKFLOW:**

**Validate Inputs:**
- Check pr_number is valid
- Verify PR exists

**[OPTIONAL] Wait for CI Completion:**

If `wait_for_ci` parameter is `true`, poll for CI completion before analyzing:

1. **Invoke the wait-for-ci operation** on the handler:
   ```bash
   # Script: plugins/repo/skills/handler-source-control-github/scripts/poll-ci-workflows.sh
   ./scripts/poll-ci-workflows.sh "$PR_NUMBER" \
     --interval "${ci_polling.interval:-60}" \
     --timeout "${ci_polling.timeout:-900}" \
     --json
   ```

2. **Handle polling results**:
   - Exit code `0` (success): CI passed, proceed to analysis
   - Exit code `4` (failed): CI failed, report and proceed to analysis (user sees failure in analysis)
   - Exit code `5` (timeout): CI still pending, report timeout warning and proceed to analysis
   - Exit code `6` (no CI): No CI configured, proceed to analysis

3. **Report CI polling status**:
   ```
   CI POLLING STATUS:
   Status: {success|failed|timeout|no_ci}
   Elapsed: {elapsed_seconds}s
   Checks: {passed}/{total} passed
   {If failed: List failed check names}
   ---
   ```

**Invoke Handler to Fetch PR Data:**

**IMPORTANT**: You MUST use the Skill tool to invoke the handler. The handler skill name is constructed as follows:
1. Read the platform from config: `config.handlers.source_control.active` (e.g., "github")
2. Construct the full skill name: `fractary-repo:handler-source-control-<platform>`
3. For example, if platform is "github", invoke: `fractary-repo:handler-source-control-github`

**DO NOT** use any other handler name pattern. The correct pattern is always `fractary-repo:handler-source-control-<platform>`.

Use the Skill tool with:
- command: `fractary-repo:handler-source-control-<platform>` (where <platform> is from config)
- Pass parameters: {pr_number}

**Analyze Response:**

The handler returns a JSON object with these fields:
```json
{
  "pr": { /* PR details */ },
  "comments": [ /* issue comments array */ ],
  "reviews": [ /* review objects array */ ],
  "review_comments": [ /* inline code review comments array */ ],
  "conflicts": { /* conflict info */ }
}
```

**STEP 1: Extract Basic PR Information**
- title: `pr.title`
- state: `pr.state`
- author: `pr.author`
- head_branch: `pr.headRefName`
- base_branch: `pr.baseRefName`
- mergeable: `pr.mergeable`
- reviewDecision: `pr.reviewDecision`

**STEP 2: Analyze Merge Conflicts**

Check `pr.mergeable` field:
- If `CONFLICTING`: Conflicts exist, must be resolved before merging
- If `MERGEABLE`: No conflicts, proceed with other checks
- If `UNKNOWN`: Conflict status unknown (GitHub still computing)

If conflicts detected (`pr.mergeable === "CONFLICTING"`):
- Extract conflicting files from `conflicts.files` array (if available)
- Note conflict details from `conflicts.details`
- Mark as: **CANNOT MERGE** - This is a blocking condition

**STEP 3: Analyze CI Status**

Extract CI status from `pr.statusCheckRollup`:
- If array is null/empty: No CI configured (proceed)
- If array contains checks with state `FAILURE` or `ERROR`: CI failures exist
- If array contains checks with state `PENDING`: CI still running
- If all checks have state `SUCCESS`: CI passing

If CI checks failing:
- List failed check names
- Mark as: **DO NOT APPROVE** - This is a blocking condition

**STEP 4: Analyze Reviews (CRITICAL - Most Important Step)**

**IMPORTANT**: This is where the previous implementation was failing. You MUST thoroughly analyze ALL reviews and comments, with special emphasis on the MOST RECENT ones.

**Review State Analysis:**
Check `reviews` array (sorted by `submitted_at` timestamp, most recent first):

1. **Find the most recent review for each reviewer**:
   - Group reviews by `user.login`
   - Take the most recent review per reviewer (highest `submitted_at` timestamp)

2. **Check review states**:
   - `APPROVED`: Reviewer approved the PR
   - `CHANGES_REQUESTED`: Reviewer explicitly requested changes (BLOCKING)
   - `COMMENTED`: Reviewer added comments without explicit approval/rejection
   - `DISMISSED`: Review was dismissed (ignore this review)

3. **Count review states**:
   - approved_count: Number of reviewers with most recent state = `APPROVED`
   - changes_requested_count: Number of reviewers with most recent state = `CHANGES_REQUESTED`
   - commented_count: Number of reviewers with most recent state = `COMMENTED`

**CRITICAL RULE**: If ANY reviewer's most recent review state is `CHANGES_REQUESTED`, this is a **BLOCKING CONDITION**. Do NOT recommend approval.

**STEP 5: Analyze Comments for Critical Issues (CRITICAL - Often Overlooked)**

**IMPORTANT**: Comments often contain detailed code review findings that don't appear in the formal review state. You MUST analyze comment content, not just review states.

**Parse ALL comments** (from `comments`, `reviews[].body`, and `review_comments` arrays):

1. **Sort all comments by timestamp** (`created_at` or `submitted_at`), most recent first

2. **Identify the most recent substantial comment** (typically the last comment from a reviewer):
   - Skip automated bot comments (unless from code review tools)
   - Skip trivial comments like "thumbs up", "LGTM", etc.
   - Focus on comments with actual feedback content (>50 characters)

3. **Analyze the most recent comment content for critical issue indicators**:

   **BLOCKING KEYWORDS** (case-insensitive search):
   - "critical issue", "critical bug", "critical problem"
   - "blocking", "blocker", "blocks"
   - "must fix", "need to fix", "needs to be fixed", "has to be fixed"
   - "security issue", "security vulnerability", "security risk"
   - "do not approve", "don't approve", "not ready", "not approved"
   - "fails", "failing", "failed" (in context of tests, not past attempts)
   - "broken", "breaks", "breaking" (in context of functionality)
   - "memory leak", "race condition", "deadlock"
   - "incorrect", "wrong", "error", "bug" (when describing current code, not fixed issues)

   **CODE REVIEW FINDINGS** (structured feedback patterns):
   - Numbered lists of issues (e.g., "1. Fix X, 2. Add Y, 3. Remove Z")
   - Bullet lists with "TODO", "FIX", "ISSUE", "PROBLEM"
   - Section headers like "Issues Found:", "Problems:", "Concerns:", "Required Changes:"
   - References to specific line numbers with required fixes
   - Mentions of missing tests, error handling, or validation

   **IMPORTANT CONTEXT CLUES**:
   - If comment says "before approving" or "before this can be merged" -> Issues are blocking
   - If comment says "nice to have" or "optional" or "future improvement" -> Issues are NOT blocking
   - If comment is from PR author -> Usually addressing feedback, not raising new issues
   - If comment is a reply in a thread -> Check if it's resolving or raising an issue

4. **Extract outstanding issues from most recent code review**:
   - If the most recent comment from a reviewer lists specific issues/tasks -> Extract them
   - If the comment explicitly says issues must be fixed -> Mark as blocking
   - If the comment is asking questions without demanding changes -> Mark as non-blocking

**STEP 6: Check Overall Review Decision**

GitHub computes an overall `pr.reviewDecision` field:
- `APPROVED`: PR has sufficient approvals and no outstanding change requests
- `CHANGES_REQUESTED`: One or more reviewers requested changes
- `REVIEW_REQUIRED`: Reviews required but not yet received
- `null`: No review requirements

**CRITICAL**: If `reviewDecision === "CHANGES_REQUESTED"`, this is a **BLOCKING CONDITION** regardless of other factors.

**Determine Recommendation:**

**Use this decision tree** (in order, first match wins):

1. **If merge conflicts detected** (`pr.mergeable === "CONFLICTING"`):
   - Recommendation: **CANNOT MERGE - RESOLVE CONFLICTS FIRST**
   - Priority: P0 (highest - blocks everything)
   - Reason: "PR has merge conflicts that must be resolved"
   - List conflicting files (if available)

2. **If CI checks are failing**:
   - Recommendation: **DO NOT APPROVE - FIX CI FAILURES FIRST**
   - Priority: P0 (highest - blocks approval)
   - Reason: "CI checks must pass before approval"
   - List failed checks

3. **If ANY reviewer has state `CHANGES_REQUESTED`** (from most recent review per reviewer):
   - Recommendation: **DO NOT APPROVE - CHANGES REQUESTED BY REVIEWERS**
   - Priority: P0 (highest - explicit block)
   - Reason: "One or more reviewers explicitly requested changes"
   - List reviewers who requested changes

4. **If `reviewDecision === "CHANGES_REQUESTED"`**:
   - Recommendation: **DO NOT APPROVE - CHANGES REQUESTED**
   - Priority: P0 (highest - GitHub-level block)
   - Reason: "GitHub review decision indicates changes are required"

5. **If most recent comment contains BLOCKING KEYWORDS or structured critical issues**:
   - Recommendation: **DO NOT APPROVE - ADDRESS CRITICAL ISSUES FIRST**
   - Priority: P1 (high - implicit block from code review)
   - Reason: "Most recent code review identified critical issues that must be addressed"
   - List outstanding issues extracted from comment

6. **If `reviewDecision === "REVIEW_REQUIRED"` and no approvals**:
   - Recommendation: **REVIEW REQUIRED - WAIT FOR APPROVALS**
   - Priority: P2 (medium - process requirement)
   - Reason: "PR requires review approval before merging"

7. **If reviewDecision === "APPROVED" OR (no review requirements AND no blocking issues)**:
   - Recommendation: **READY TO APPROVE**
   - Priority: P3 (normal - can proceed)
   - Reason: "All checks passed, no blocking issues identified"

**Present Analysis to User:**

Show structured analysis with **all relevant details** from the analysis steps above:

```
PR ANALYSIS: #{pr_number}
Title: {title}
Branch: {head_branch} -> {base_branch}
Author: {author}
Status: {state} {isDraft ? "(DRAFT)" : ""}
URL: {url}
---

MERGE STATUS:
{Mergeable status - MERGEABLE, CONFLICTING, or UNKNOWN}
{If conflicts detected:}
  Merge conflicts detected
  {If conflicting files available:}
  Conflicting files:
  {List each conflicting file}
  {conflict_details if available}

CI STATUS:
{If no CI checks configured:}
  No CI checks configured

{If CI checks exist:}
  {For each check in statusCheckRollup:}
  - {check_name}: {status} {conclusion}

  Summary: {X passing, Y failing, Z pending}

REVIEW STATUS:
Overall Decision: {reviewDecision or "No review requirements"}

{If reviews exist:}
Reviews by user (most recent state):
{For each reviewer with their most recent review:}
- {reviewer_name}: {state} {submitted_at}
  {If review has body/comment:}
  Comment: "{truncated comment preview}"

Summary:
- Approved: {approved_count}
- Changes Requested: {changes_requested_count}
- Commented: {commented_count}

{If no reviews:}
  No reviews submitted yet

COMMENT ANALYSIS:
{If substantial comments exist:}
Total comments: {total comment count}

Most Recent Substantial Comment:
  From: {author}
  Date: {timestamp}
  {If blocking keywords found:}
  BLOCKING INDICATORS DETECTED: {list keywords found}

  Content Preview:
  {Show first 200-300 chars or key excerpts}

  {If structured issues extracted:}
  Outstanding Issues Identified:
  {List each extracted issue/task}

{If no substantial comments:}
  No substantial code review comments

CRITICAL ISSUES SUMMARY:
{Compile all blocking issues from above analysis:}
{If conflicts:}
- Merge conflicts must be resolved

{If CI failures:}
- CI checks failing: {list failed check names}

{If changes requested:}
- Changes explicitly requested by: {list reviewers}

{If critical issues in comments:}
- Code review identified critical issues:
  {List outstanding issues from comment analysis}

{If no critical issues:}
No critical issues identified

---
RECOMMENDATION: {RECOMMENDATION}
Priority: {P0/P1/P2/P3}
Reason: {Detailed reason from decision tree}

---
SUGGESTED NEXT STEPS:

{If merge conflicts exist:}
1. [RESOLVE CONFLICTS] Fix merge conflicts on branch {head_branch}
   Steps:
   a. Switch to branch: git checkout {head_branch}
   b. Pull latest changes: git pull origin {head_branch}
   c. Merge base branch: git merge origin/{base_branch}
   d. Resolve conflicts in: {list conflicting files}
   e. Commit resolution: git commit
   f. Push changes: git push origin {head_branch}
   g. Wait for CI to pass and re-analyze: /repo:pr-review {pr_number}

{Else if CI failures exist:}
1. [FIX CI] Address failing CI checks
   Failed checks: {list failed checks}
   View details: {pr_url}/checks
   Fix issues on branch {head_branch}

2. [RE-ANALYZE] After fixes, re-run analysis
   Use: /repo:pr-review {pr_number}

{Else if changes requested or critical issues in comments:}
1. [ADDRESS ISSUES] Fix the issues identified in code review
   {If specific issues listed:}
   Issues to address:
   {List each issue as a checkbox/action item}

   Work on branch: {head_branch}

2. [RE-ANALYZE] After fixes, re-run analysis
   Use: /repo:pr-review {pr_number}

3. [DISCUSS] If you disagree with the feedback
   Add comment to discuss: /repo:pr-comment {pr_number} --comment "Your response"

{Else if review required but no reviews:}
1. [WAIT FOR REVIEW] PR requires review approval
   Request review from team members

2. [CHECK STATUS] Monitor review status
   Use: /repo:pr-review {pr_number}

{Else if ready to approve:}
1. [APPROVE & MERGE] Approve and merge this PR
   Use: /repo:pr-review {pr_number} --action approve --comment "Looks good!"
   Then: /repo:pr-merge {pr_number}

2. [REQUEST CHANGES] Request additional changes (if you found issues)
   Use: /repo:pr-review {pr_number} --action request_changes --comment "Your feedback"

3. [ADD COMMENT] Add comment without formal review
   Use: /repo:pr-comment {pr_number} --comment "Your feedback"
```

**CRITICAL OUTPUT REQUIREMENTS:**

1. **Always show the most recent comment analysis** - This is often where critical issues are documented
2. **Always extract and display outstanding issues** from comments if they exist
3. **Always justify the recommendation** with specific evidence from the analysis
4. **Never recommend approval** if Step 5 (comment analysis) found blocking indicators
5. **Show specific reviewers** who requested changes or approved
6. **Include timestamps** to show recency of feedback

**4B. CREATE PR WORKFLOW:**

**Check for Existing PR (Self-Contained Idempotency):**

BEFORE any validation, check if a PR already exists for this branch:

```
1. Invoke handler to list PRs for head_branch -> base_branch
2. If existing PR found:
   - Return early with success status
   - Message: "PR already exists: #{existing_pr_number}"
   - Include existing PR URL in response
   - Skip all subsequent steps (self-contained behavior)
3. If no existing PR -> continue with creation
```

This self-contained check ensures:
- The step is idempotent (safe to call multiple times)
- Workflow orchestrators don't need conditional logic
- Resume/retry scenarios work correctly

**Resolve work_id (CRITICAL for issue auto-close - Issue #303):**

The work_id is essential for automatic issue closing when the PR is merged.
Follow this resolution order:

```
1. Check if work_id is explicitly provided in parameters
   - If present and non-empty: use it directly
   - Log: "work_id: {work_id} (explicit)"

2. If work_id NOT provided, check step arguments from workflow context
   - Workflow steps can pass arguments: {"work_id": "{work_id}"}
   - If present in arguments: use it
   - Log: "work_id: {work_id} (from workflow arguments)"

3. If still no work_id, attempt fallback extraction from branch name
   - Pattern: prefix/ID-description (e.g., "fix/303-issue-linking", "feat/123-add-export")
   - Extract numeric ID after the first "/" and before the first "-"
   - Regex: /^[a-z]+\/(\d+)-/i captures the ID
   - If match found: use extracted ID as work_id
   - Log WARNING: "work_id: {work_id} (extracted from branch name - not explicit)"

4. If work_id still cannot be determined:
   - Log ERROR: "work_id could not be determined"
   - Show clear message: "Cannot create PR without work_id for issue linking.
     Provide work_id explicitly or use branch naming convention: prefix/ID-description"
   - Return failure response with suggested fixes
```

**Example branch name extraction:**
- `fix/303-issue-branch-linking` -> work_id = "303"
- `feat/123-add-csv-export` -> work_id = "123"
- `chore/456-update-deps` -> work_id = "456"
- `main` -> no match, work_id = null

**Validate Inputs:**
- Check title is non-empty
- Verify head_branch exists and has commits
- Verify base_branch exists
- Check work_id is present (after resolution above)

**Check Protected Base Branch:**
If base_branch is protected:
- Warn user
- Require explicit confirmation
- Validate review requirements configured

**Format PR Body:**
Use PR body template with resolved work_id:

```markdown
## Summary
{summary_from_body_or_title}

## Changes
{detailed_changes}

## Testing
{testing_performed}

## Work Item
Closes #{work_id}

## Metadata
- Branch: {head_branch}
- Base: {base_branch}
- Author Context: {author_context}
- Phase: {phase}
- Created: {timestamp}

---
Generated by FABER workflow
```

**CRITICAL**: The "Closes #{work_id}" line enables GitHub's automatic issue closing feature.
When the PR is merged, GitHub will automatically close issue #{work_id}.

**Invoke Handler:**

**IMPORTANT**: You MUST use the Skill tool. Construct the full skill name as `fractary-repo:handler-source-control-<platform>` where <platform> is from `config.handlers.source_control.active`.

Use the Skill tool with:
- command: `fractary-repo:handler-source-control-<platform>`
- Pass parameters: {title, formatted_body, head_branch, base_branch, draft}

**4C. COMMENT PR WORKFLOW:**

**Validate Inputs:**
- Check pr_number is valid
- Verify comment is non-empty
- Check PR exists

**Invoke Handler:**

Use the Skill tool with command `fractary-repo:handler-source-control-<platform>` where <platform> is from config.
Pass parameters: {pr_number, comment}

**4D. REVIEW PR WORKFLOW:**

**Validate Inputs:**
- Check pr_number is valid
- Verify action is valid (approve|request_changes|comment)
- Check comment is non-empty if action is request_changes

**CRITICAL: DO NOT check PR authorship**
- NEVER preemptively block approval based on PR author
- NEVER compare PR author with current user
- Let the platform API handle authorship validation
- Only show "can't approve own PR" if the platform returns that specific error
- Trust the platform to enforce its own policies

**Invoke Handler:**

Use the Skill tool with command `fractary-repo:handler-source-control-<platform>` where <platform> is from config.
Pass parameters: {pr_number, action, comment}

**Handle Response:**
- If handler succeeds: Report success
- If handler fails with "can't review own PR": Pass through that error
- Otherwise: Report the actual error from the platform

**4E. MERGE PR WORKFLOW:**

**Validate Inputs:**
- Check pr_number is valid
- Verify merge strategy is valid (merge|squash|rebase or no-ff|squash|ff-only)
- Note: Map no-ff->merge, ff-only->rebase if needed for handler compatibility
- Check PR exists and is mergeable

**Check Merge Requirements:**
- Verify CI status is passing
- Check required reviews are approved
- Verify no merge conflicts
- Validate target branch protection rules

**MANDATORY APPROVAL GATE FOR PROTECTED BRANCHES (Issue #297):**

**CRITICAL: This is the enforcement point for approval gates.**

If merging to a protected branch (main, master, production, staging):

1. **STOP and emit decision_point event** (if in workflow context):
   ```
   Emit event: decision_point
   Phase: release
   Message: "Release to {base_branch} requires approval"
   ```

2. **MANDATORY: Invoke AskUserQuestion** (do NOT proceed without explicit approval):
   ```
   question: "Release PR #{pr_number} to protected branch '{base_branch}'?"
   header: "Protected Branch Release Approval"
   options:
     - label: "Approve release"
       description: "Authorize merge to {base_branch}"
     - label: "Cancel"
       description: "Do not merge at this time"
   multiSelect: false
   ```

3. **Handle user response**:
   - If user selects "Cancel": STOP workflow, do not merge
   - If user selects "Approve release": Continue to step 4 with approval granted

   **CRITICAL**: Do NOT proceed without explicit user selection "Approve release"

4. **Set environment variable for script-level enforcement**:
   After user approves, export:
   ```bash
   export FABER_RELEASE_APPROVED=true
   ```
   This variable MUST be set before invoking the merge script.
   The script will reject the merge if this variable is not set to "true".

5. **Emit approval_granted event** (for audit trail):
   ```
   Emit event: approval_granted
   Phase: release
   Message: "User approved release to {base_branch}"
   ```

**Non-Protected Branches:**
For non-protected branches (feature, staging, dev, etc.):
- Proceed directly to handler invocation (no approval gate required)
- Handler will still enforce requirements via script validation

**Invoke Handler:**

Use the Skill tool with command `fractary-repo:handler-source-control-<platform>` where <platform> is from config.

Pass parameters: {pr_number, strategy, delete_branch}

**CRITICAL**: The handler script now enforces approval via FABER_RELEASE_APPROVED environment variable.
If merging to a protected branch without this variable set, the script will exit with code 16 (approval required).
This provides defense-in-depth protection against bypass attempts.

**Note**: The handler script automatically maps strategy names:
- `no-ff` or `merge` -> GitHub's `--merge` flag
- `squash` -> GitHub's `--squash` flag
- `ff-only` or `rebase` -> GitHub's `--rebase` flag

No manual mapping is needed - the script handles this internally.

**Post-Merge Cleanup:**
If delete_branch=true and merge successful:
- The handler automatically deletes the remote branch via `gh pr merge --delete-branch`
- No additional cleanup needed

**5. VALIDATE RESPONSE:**

- Check handler returned success status
- Verify PR operation completed
- Capture PR number/URL
- Confirm expected state changes

**5A. UPDATE REPO CACHE (for create-pr operation):**

After successful PR creation, update the repo plugin cache to include the PR number:

```bash
# Update repo cache to include new PR number
plugins/repo/scripts/update-status-cache.sh --quiet
```

This proactively updates:
- PR number (newly created PR)
- Ensures work plugin and other consumers can access PR info immediately

**6. OUTPUT COMPLETION MESSAGE:**

```
COMPLETED: PR Manager
Operation: {operation}
PR: #{pr_number}
URL: {pr_url}
Status: {status}
---
Next: {next_action}
```

</WORKFLOW>

<COMPLETION_CRITERIA>

**For Analyze PR:**
- PR details fetched successfully
- Comments and reviews retrieved
- Merge conflict status checked
- CI status analyzed
- Code review findings summarized
- Recommendation generated (with conflict resolution if needed)
- Next steps presented to user

**For Create PR:**
- PR created successfully
- Work item linked (with "Closes #{work_id}" in body)
- PR body formatted correctly
- PR URL captured

**For Comment PR:**
- Comment added successfully
- Comment URL captured

**For Review PR:**
- Review submitted successfully
- Review status recorded

**For Merge PR:**
- CI status verified passing
- Reviews approved
- PR merged successfully
- Branch deleted if requested
- Merge SHA captured
- **For protected branches: User approval explicitly obtained via AskUserQuestion**
- **Approval environment variable set before handler invocation**

</COMPLETION_CRITERIA>

<OUTPUTS>
Return results using the **standard FABER response format**.

See: `plugins/faber/docs/RESPONSE-FORMAT.md` for complete specification.

**Success Response (Create PR):**
```json
{
  "status": "success",
  "message": "PR #456 created: feat/123-add-export -> main",
  "details": {
    "operation": "create-pr",
    "pr_number": 456,
    "pr_url": "https://github.com/owner/repo/pull/456",
    "head_branch": "feat/123-add-export",
    "base_branch": "main",
    "work_id": "#123",
    "work_id_source": "explicit",
    "draft": false,
    "platform": "github"
  }
}
```

**Success Response (Create PR with Fallback work_id):**
```json
{
  "status": "warning",
  "message": "PR #456 created: feat/123-add-export -> main (work_id extracted from branch)",
  "details": {
    "operation": "create-pr",
    "pr_number": 456,
    "pr_url": "https://github.com/owner/repo/pull/456",
    "head_branch": "feat/123-add-export",
    "base_branch": "main",
    "work_id": "#123",
    "work_id_source": "branch_name_fallback",
    "draft": false,
    "platform": "github"
  },
  "warnings": [
    "work_id was extracted from branch name, not provided explicitly"
  ],
  "warning_analysis": "PR created successfully, but work_id was inferred from branch naming convention rather than explicit parameter",
  "suggested_fixes": [
    "For future PRs, pass work_id explicitly in workflow config",
    "Verify issue #123 is correctly linked in PR body"
  ]
}
```

**Success Response (Analyze PR):**
```json
{
  "status": "success",
  "message": "PR #456 analyzed: READY_TO_APPROVE",
  "details": {
    "operation": "analyze-pr",
    "pr_number": 456,
    "analysis": {
      "title": "Add CSV export feature",
      "head_branch": "feat/123-add-export",
      "base_branch": "main",
      "author": "username",
      "state": "OPEN",
      "mergeable": "MERGEABLE",
      "conflicts": {"detected": false, "files": []},
      "reviewDecision": "APPROVED",
      "ci_status": "passing",
      "outstanding_issues": [],
      "recommendation": "READY_TO_APPROVE"
    },
    "suggested_actions": [
      {"action": "approve_and_merge", "commands": ["/repo:pr-review 456 approve", "/repo:pr-merge 456"]}
    ]
  }
}
```

**Success Response (Merge PR):**
```json
{
  "status": "success",
  "message": "PR #456 merged to main using no-ff strategy",
  "details": {
    "operation": "merge-pr",
    "pr_number": 456,
    "merge_sha": "abc123def456...",
    "strategy": "no-ff",
    "branch_deleted": true,
    "merged_at": "2025-10-29T12:00:00Z"
  }
}
```

**Warning Response (Merge with Branch Deletion Skipped):**
```json
{
  "status": "warning",
  "message": "PR #456 merged but branch not deleted",
  "details": {
    "operation": "merge-pr",
    "pr_number": 456,
    "merge_sha": "abc123def456...",
    "strategy": "squash",
    "branch_deleted": false
  },
  "warnings": [
    "Branch 'feat/123-add-export' was not deleted due to protection rules"
  ],
  "warning_analysis": "The branch has additional protection that prevents automatic deletion",
  "suggested_fixes": [
    "Manually delete branch: git push origin --delete feat/123-add-export",
    "Check branch protection rules in repository settings"
  ]
}
```

**Failure Response (Missing work_id):**
```json
{
  "status": "failure",
  "message": "Cannot create PR - work_id could not be determined",
  "details": {
    "operation": "create-pr",
    "head_branch": "main",
    "base_branch": "develop"
  },
  "errors": [
    "work_id is required for PR creation to enable automatic issue closing",
    "Branch name 'main' does not follow pattern: prefix/ID-description"
  ],
  "error_analysis": "PR creation requires work_id to link to an issue. It was not provided explicitly and could not be extracted from branch name.",
  "suggested_fixes": [
    "Provide work_id explicitly: --work-id 123",
    "Use branch naming convention: fix/123-description or feat/456-feature-name",
    "Create PR from a feature branch, not main"
  ]
}
```

**Failure Response (Merge Conflicts):**
```json
{
  "status": "failure",
  "message": "PR #456 cannot be merged - merge conflicts detected",
  "details": {
    "operation": "merge-pr",
    "pr_number": 456,
    "mergeable": "CONFLICTING"
  },
  "errors": [
    "Merge conflict in src/export.js",
    "Merge conflict in src/utils.js"
  ],
  "error_analysis": "The head branch has diverged from base branch and has conflicting changes in 2 files",
  "suggested_fixes": [
    "Checkout branch: git checkout feat/123-add-export",
    "Pull latest base: git merge origin/main",
    "Resolve conflicts in conflicting files",
    "Push resolved changes: git push"
  ]
}
```

**Failure Response (CI Not Passing):**
```json
{
  "status": "failure",
  "message": "PR #456 cannot be merged - CI checks failing",
  "details": {
    "operation": "merge-pr",
    "pr_number": 456,
    "ci_status": "failing"
  },
  "errors": [
    "Check 'build' failed: Exit code 1",
    "Check 'test' failed: 3 tests failed"
  ],
  "error_analysis": "Required CI checks must pass before merging. Build and test checks are currently failing.",
  "suggested_fixes": [
    "View CI details at PR URL",
    "Fix failing tests and push changes",
    "Re-run CI checks after fixes"
  ]
}
```

**Failure Response (PR Not Found):**
```json
{
  "status": "failure",
  "message": "PR #999 not found",
  "details": {
    "operation": "analyze-pr",
    "pr_number": 999
  },
  "errors": [
    "Pull request #999 does not exist in this repository"
  ],
  "error_analysis": "The specified PR number does not exist or may have been deleted",
  "suggested_fixes": [
    "Verify PR number is correct",
    "Check if PR was closed or deleted",
    "List open PRs: gh pr list"
  ]
}
```

</OUTPUTS>

<HANDLERS>
This skill uses the handler pattern to support multiple platforms:

- **handler-source-control-github**: GitHub PR operations via gh CLI
- **handler-source-control-gitlab**: GitLab MR operations (stub)
- **handler-source-control-bitbucket**: Bitbucket PR operations (stub)

The active handler is determined by configuration: `config.handlers.source_control.active`
</HANDLERS>

<ERROR_HANDLING>

**Invalid Inputs** (Exit Code 2):
- Missing title: "Error: PR title is required"
- Missing head_branch: "Error: head_branch is required"
- Missing base_branch: "Error: base_branch is required"
- Missing work_id: "Error: work_id is required for issue linking. Provide explicitly or use branch pattern: prefix/ID-description"
- Invalid pr_number: "Error: PR number must be a positive integer"
- Invalid action: "Error: Invalid review action. Valid: approve|request_changes|comment"
- Invalid strategy: "Error: Invalid merge strategy. Valid: no-ff|squash|ff-only"

**Branch Errors** (Exit Code 1):
- Head branch doesn't exist: "Error: Head branch not found: {head_branch}"
- Base branch doesn't exist: "Error: Base branch not found: {base_branch}"
- No commits to merge: "Error: Head branch has no new commits compared to base"

**PR Not Found** (Exit Code 1):
- Invalid PR: "Error: Pull request not found: #{pr_number}"
- PR already merged: "Error: Pull request already merged: #{pr_number}"
- PR closed: "Error: Pull request is closed: #{pr_number}"

**Merge Conflicts** (Exit Code 13):
- Conflicts detected: "Error: Pull request has merge conflicts. Resolve conflicts first."
- Cannot auto-merge: "Error: Pull request cannot be automatically merged"

**CI Failures** (Exit Code 14):
- CI not passing: "Error: CI checks are not passing. Cannot merge."
- Required checks missing: "Error: Required status checks have not passed"

**Review Requirements** (Exit Code 15):
- Insufficient reviews: "Error: Pull request requires {N} approving reviews before merging"
- Changes requested: "Error: Pull request has requested changes that must be resolved"

**Protected Branch** (Exit Code 10):
- Protected target: "Warning: Creating PR to protected branch: {base_branch}. Confirm requirements."
- Force merge blocked: "Error: Cannot force merge to protected branch: {base_branch}"

**Approval Required** (Exit Code 16):
- Protected branch without approval: "Error: Cannot merge PR #{pr_number} to protected branch '{base_branch}' without approval. Set FABER_RELEASE_APPROVED=true after obtaining explicit user confirmation."

**Authentication Error** (Exit Code 11):
- No credentials: "Error: Platform API credentials not found"
- Permission denied: "Error: Insufficient permissions to create/merge PR"

**Handler Error** (Exit Code 1):
- Pass through handler error: "Error: Handler failed - {handler_error}"

</ERROR_HANDLING>

<USAGE_EXAMPLES>

**Example 1a: Analyze PR (with conflicts)**
```
INPUT:
{
  "operation": "analyze-pr",
  "parameters": {
    "pr_number": 456
  }
}

OUTPUT:
{
  "status": "success",
  "pr_number": 456,
  "analysis": {
    "title": "Add CSV export functionality",
    "state": "OPEN",
    "mergeable": "CONFLICTING",
    "conflicts": {
      "detected": true,
      "files": ["src/export.js", "src/utils.js"]
    },
    "ci_status": "pending",
    "reviewDecision": "REVIEW_REQUIRED",
    "recommendation": "RESOLVE_CONFLICTS_FIRST"
  }
}
```

**Example 1b: Analyze PR (with code review issues in comments)**
```
INPUT:
{
  "operation": "analyze-pr",
  "parameters": {
    "pr_number": 456
  }
}

SCENARIO:
- PR is mergeable (no conflicts)
- CI checks are passing
- No formal CHANGES_REQUESTED review state
- BUT: Most recent comment from reviewer contains critical issues

HANDLER RESPONSE:
{
  "pr": {
    "mergeable": "MERGEABLE",
    "reviewDecision": null,
    "statusCheckRollup": [{"state": "SUCCESS"}]
  },
  "comments": [
    {
      "author": {"login": "reviewer1"},
      "created_at": "2025-11-19T10:30:00Z",
      "body": "I've reviewed the code and found several critical issues that must be fixed before this can be approved:\n\n1. Missing error handling for large files (>100MB) - this will cause memory issues\n2. No validation for malformed CSV input - security vulnerability\n3. Unit tests don't cover edge cases (empty files, special characters)\n4. The export function doesn't handle concurrent requests properly\n\nPlease address these before we proceed with approval."
    }
  ],
  "reviews": [],
  "review_comments": []
}

SKILL ANALYSIS (Step 5 - Comment Analysis):
- Most recent comment from: reviewer1
- Timestamp: 2025-11-19T10:30:00Z
- BLOCKING KEYWORDS FOUND: "critical issues", "must be fixed", "before this can be approved"
- STRUCTURED ISSUES FOUND: Numbered list with 4 specific issues
- Context clues: "before we proceed with approval" -> BLOCKING

RECOMMENDATION (from decision tree step 5):
"DO NOT APPROVE - ADDRESS CRITICAL ISSUES FIRST"

OUTPUT:
{
  "status": "success",
  "pr_number": 456,
  "analysis": {
    "title": "Add CSV export functionality",
    "state": "OPEN",
    "mergeable": "MERGEABLE",
    "conflicts": {
      "detected": false,
      "files": []
    },
    "ci_status": "passing",
    "reviewDecision": null,
    "comment_analysis": {
      "most_recent_comment": {
        "author": "reviewer1",
        "timestamp": "2025-11-19T10:30:00Z",
        "blocking_keywords": ["critical issues", "must be fixed", "before this can be approved"]
      },
      "outstanding_issues": [
        "Missing error handling for large files (>100MB) - this will cause memory issues",
        "No validation for malformed CSV input - security vulnerability",
        "Unit tests don't cover edge cases (empty files, special characters)",
        "The export function doesn't handle concurrent requests properly"
      ]
    },
    "recommendation": "DO_NOT_APPROVE",
    "priority": "P1",
    "reason": "Most recent code review identified critical issues that must be addressed"
  }
}
```

**Example 2: Create PR 

…(truncated)
