Skip to content

Skip issues with existing PRs and ignore non-agent-owned PRs #4

@qinqon

Description

@qinqon

Problem

Currently the agent has two gaps in how it handles PRs:

1. Agent creates duplicate PRs for issues that already have one

ProcessNewIssues only checks for existing PRs by matching the agent's branch name pattern (ai/issue-N) via ListPRsByHead. If a human or another bot has already opened a PR that closes the issue, the agent creates a second, redundant PR.

Current code (loop.go:86-100):

branchName := fmt.Sprintf("ai/issue-%d", issue.Number)
prs, err := a.gh.ListPRsByHead(ctx, a.cfg.Owner, a.cfg.Repo, a.cfg.GitHubHeadOwner, branchName)
if err == nil && len(prs) > 0 {
    // only matches ai/issue-N branches
}

2. Agent processes review comments/CI/conflicts on PRs it doesn't own

If a non-agent PR somehow gets tracked in state (e.g., through a future code path or state rebuild), ProcessReviewComments, ProcessCIFailures, and ProcessConflicts would try to address feedback, fix CI, and resolve conflicts on a PR the agent didn't create. This wastes resources and could interfere with human work.

Proposed Solution

Skip issues that already have a closing PR

Before creating a worktree and invoking Claude for an issue, check whether any open PR already closes it. GitHub's Timeline API (GET /repos/{owner}/{repo}/issues/{issue_number}/timeline) includes cross-referenced events with source.issue.pull_request that link PRs to issues. Alternatively, use the GraphQL API's closingReferencesConnection on the Issue type.

Add a new method to GitHubClient:

ListClosingPRs(ctx context.Context, owner, repo string, issueNumber int) ([]PR, error)

In ProcessNewIssues, after confirming the issue is not in state and before creating a worktree:

  • Call ListClosingPRs to find any open PR that would close the issue
  • If one exists, log it and skip the issue (do not add to state, do not invoke Claude)

Track PR ownership and skip non-agent PRs

Add an OwnedByAgent bool field to IssueWork to track whether the agent created the PR. Set it to true when the agent creates the PR via Claude, and false when recovering state from a PR the agent didn't create.

In ProcessReviewComments, ProcessCIFailures, and ProcessConflicts:

  • Skip work items where OwnedByAgent == false

In BuildStateFromGitHub (state.go):

  • When recovering PRs, check if the PR's head branch matches the ai/issue-N pattern and the PR author matches cfg.GitHubUser to determine ownership

Files to change

File Change
pkg/agent/types.go Add OwnedByAgent bool to IssueWork
pkg/agent/github.go Add ListClosingPRs to GitHubClient interface + implementation
pkg/agent/loop.go Call ListClosingPRs in ProcessNewIssues before creating worktree; set OwnedByAgent = true when agent creates PR; skip non-owned PRs in ProcessReviewComments, ProcessCIFailures, ProcessConflicts
pkg/agent/state.go Set OwnedByAgent correctly in BuildStateFromGitHub
pkg/agent/loop_test.go Add tests for skipping issues with existing closing PRs and skipping non-owned PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions