diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml index 52a01c4bc2a..bfe28e24d60 100644 --- a/.github/workflows/issue-monster.lock.yml +++ b/.github/workflows/issue-monster.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"eac7305dc9f610adb3d3359f9367aca98730d48712f510c74e8523a3c70facf3","strict":true,"agent_id":"copilot","agent_model":"gpt-5.1-codex-mini"} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"d10076fe5d53fb3703246a470b8702dfe80f8d1d2f7f209456cb47e04446c174","strict":true,"agent_id":"copilot","agent_model":"claude-haiku-4.5"} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_AGENT_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.24"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.24"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.24"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.24"},{"image":"ghcr.io/github/github-mcp-server:v1.0.0"},{"image":"node:lts-alpine","digest":"sha256:01743339035a5c3c11a373cd7c83aeab6ed1457b55da6a69e014a95ac4e4700b","pinned_image":"node:lts-alpine@sha256:01743339035a5c3c11a373cd7c83aeab6ed1457b55da6a69e014a95ac4e4700b"}]} # ___ _ _ # / _ \ | | (_) @@ -76,6 +76,8 @@ name: "Issue Monster" # with: # script: | # const { owner, repo } = context.repo; + # const MAX_ISSUES_WITH_BODY_CONTEXT = 8; + # const BODY_SNIPPET_MAX_LENGTH = 600; # # try { # // Check for recent rate-limited PRs to avoid scheduling more work during rate limiting @@ -145,6 +147,7 @@ name: "Issue Monster" # core.setOutput('issue_count', 0); # core.setOutput('issue_numbers', ''); # core.setOutput('issue_list', ''); + # core.setOutput('issue_context', ''); # core.setOutput('has_issues', 'false'); # return; # } @@ -381,6 +384,7 @@ name: "Issue Monster" # number: issue.number, # title: issue.title, # labels: issue.labels.map(l => l.name), + # body: issue.body, # created_at: issue.created_at, # score # }; @@ -392,6 +396,15 @@ name: "Issue Monster" # const labelStr = i.labels.length > 0 ? ` [${i.labels.join(', ')}]` : ''; # return `#${i.number}: ${i.title}${labelStr} (score: ${i.score.toFixed(1)})`; # }).join('\n'); + # + # // Pre-fetch compact body context for top candidates so the agent can + # // triage without extra reads in most runs. + # const issueContext = scoredIssues.slice(0, MAX_ISSUES_WITH_BODY_CONTEXT).map(i => { + # const body = (i.body || '').replace(/\s+/g, ' ').trim(); + # const bodySnippet = body.length > BODY_SNIPPET_MAX_LENGTH ? `${body.slice(0, BODY_SNIPPET_MAX_LENGTH)}…` : body; + # const labelStr = i.labels.length > 0 ? i.labels.join(', ') : 'none'; + # return `#${i.number} | score=${i.score.toFixed(1)} | labels=${labelStr}\nTitle: ${i.title}\nBody: ${bodySnippet || '(no body)'}`; + # }).join('\n\n---\n\n'); # # const issueNumbers = scoredIssues.map(i => i.number).join(','); # @@ -403,6 +416,7 @@ name: "Issue Monster" # core.setOutput('issue_count', scoredIssues.length); # core.setOutput('issue_numbers', issueNumbers); # core.setOutput('issue_list', issueList); + # core.setOutput('issue_context', issueContext); # # if (scoredIssues.length === 0) { # core.info('🍽️ No suitable candidate issues - the plate is empty!'); @@ -415,6 +429,7 @@ name: "Issue Monster" # core.setOutput('issue_count', 0); # core.setOutput('issue_numbers', ''); # core.setOutput('issue_list', ''); + # core.setOutput('issue_context', ''); # core.setOutput('has_issues', 'false'); # } workflow_dispatch: @@ -468,7 +483,7 @@ jobs: env: GH_AW_INFO_ENGINE_ID: "copilot" GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" - GH_AW_INFO_MODEL: "gpt-5.1-codex-mini" + GH_AW_INFO_MODEL: "claude-haiku-4.5" GH_AW_INFO_VERSION: "1.0.21" GH_AW_INFO_AGENT_VERSION: "1.0.21" GH_AW_INFO_WORKFLOW_NAME: "Issue Monster" @@ -537,6 +552,7 @@ jobs: GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} + GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_CONTEXT: ${{ needs.pre_activation.outputs.issue_context }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_COUNT: ${{ needs.pre_activation.outputs.issue_count }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_LIST: ${{ needs.pre_activation.outputs.issue_list }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_NUMBERS: ${{ needs.pre_activation.outputs.issue_numbers }} @@ -544,20 +560,20 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_f8901b6202eb9fe6_EOF' + cat << 'GH_AW_PROMPT_e301ff5ec303eb90_EOF' - GH_AW_PROMPT_f8901b6202eb9fe6_EOF + GH_AW_PROMPT_e301ff5ec303eb90_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_f8901b6202eb9fe6_EOF' + cat << 'GH_AW_PROMPT_e301ff5ec303eb90_EOF' Tools: add_comment(max:3), assign_to_agent(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_f8901b6202eb9fe6_EOF + GH_AW_PROMPT_e301ff5ec303eb90_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_f8901b6202eb9fe6_EOF' + cat << 'GH_AW_PROMPT_e301ff5ec303eb90_EOF' The following GitHub context information is available for this workflow: {{#if __GH_AW_GITHUB_ACTOR__ }} @@ -586,20 +602,21 @@ jobs: {{/if}} - GH_AW_PROMPT_f8901b6202eb9fe6_EOF + GH_AW_PROMPT_e301ff5ec303eb90_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_f8901b6202eb9fe6_EOF' + cat << 'GH_AW_PROMPT_e301ff5ec303eb90_EOF' {{#runtime-import .github/workflows/shared/github-guard-policy.md}} {{#runtime-import .github/workflows/shared/activation-app.md}} {{#runtime-import .github/workflows/issue-monster.md}} - GH_AW_PROMPT_f8901b6202eb9fe6_EOF + GH_AW_PROMPT_e301ff5ec303eb90_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} + GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_CONTEXT: ${{ needs.pre_activation.outputs.issue_context }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_COUNT: ${{ needs.pre_activation.outputs.issue_count }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_LIST: ${{ needs.pre_activation.outputs.issue_list }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_NUMBERS: ${{ needs.pre_activation.outputs.issue_numbers }} @@ -623,6 +640,7 @@ jobs: GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} + GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_CONTEXT: ${{ needs.pre_activation.outputs.issue_context }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_COUNT: ${{ needs.pre_activation.outputs.issue_count }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_LIST: ${{ needs.pre_activation.outputs.issue_list }} GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_NUMBERS: ${{ needs.pre_activation.outputs.issue_numbers }} @@ -647,6 +665,7 @@ jobs: GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST, GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED, + GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_CONTEXT: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_CONTEXT, GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_COUNT: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_COUNT, GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_LIST: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_LIST, GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_NUMBERS: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ISSUE_NUMBERS @@ -782,9 +801,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_c922b5e93a111615_EOF' + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_8c9d5b9222cb4f50_EOF' {"add_comment":{"max":3,"target":"*"},"assign_to_agent":{"allowed":["copilot"],"max":3,"target":"*"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_c922b5e93a111615_EOF + GH_AW_SAFE_OUTPUTS_CONFIG_8c9d5b9222cb4f50_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -996,7 +1015,7 @@ jobs: mkdir -p /home/runner/.copilot GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) - cat << GH_AW_MCP_CONFIG_f578c422c31b5a81_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" + cat << GH_AW_MCP_CONFIG_214645539377f980_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" { "mcpServers": { "github": { @@ -1006,7 +1025,7 @@ jobs: "GITHUB_HOST": "\${GITHUB_SERVER_URL}", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" + "GITHUB_TOOLSETS": "issues" }, "guard-policies": { "allow-only": { @@ -1040,7 +1059,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_f578c422c31b5a81_EOF + GH_AW_MCP_CONFIG_214645539377f980_EOF - name: Mount MCP servers as CLIs id: mount-mcp-clis continue-on-error: true @@ -1085,7 +1104,7 @@ jobs: env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: gpt-5.1-codex-mini + COPILOT_MODEL: claude-haiku-4.5 GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json GH_AW_PHASE: agent GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -1529,7 +1548,7 @@ jobs: env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - COPILOT_MODEL: gpt-5.1-codex-mini + COPILOT_MODEL: claude-haiku-4.5 GH_AW_PHASE: detection GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GH_AW_VERSION: dev @@ -1576,6 +1595,7 @@ jobs: outputs: activated: ${{ steps.check_membership.outputs.is_team_member == 'true' && steps.check_skip_if_match.outputs.skip_check_ok == 'true' && steps.check_skip_if_no_match.outputs.skip_no_match_check_ok == 'true' && steps.check_skip_if_check_failing.outputs.skip_if_check_failing_ok == 'true' }} has_issues: ${{ steps.search.outputs.has_issues }} + issue_context: ${{ steps.search.outputs.issue_context }} issue_count: ${{ steps.search.outputs.issue_count }} issue_list: ${{ steps.search.outputs.issue_list }} issue_numbers: ${{ steps.search.outputs.issue_numbers }} @@ -1652,6 +1672,8 @@ jobs: with: script: | const { owner, repo } = context.repo; + const MAX_ISSUES_WITH_BODY_CONTEXT = 8; + const BODY_SNIPPET_MAX_LENGTH = 600; try { // Check for recent rate-limited PRs to avoid scheduling more work during rate limiting @@ -1721,6 +1743,7 @@ jobs: core.setOutput('issue_count', 0); core.setOutput('issue_numbers', ''); core.setOutput('issue_list', ''); + core.setOutput('issue_context', ''); core.setOutput('has_issues', 'false'); return; } @@ -1957,6 +1980,7 @@ jobs: number: issue.number, title: issue.title, labels: issue.labels.map(l => l.name), + body: issue.body, created_at: issue.created_at, score }; @@ -1969,6 +1993,15 @@ jobs: return `#${i.number}: ${i.title}${labelStr} (score: ${i.score.toFixed(1)})`; }).join('\n'); + // Pre-fetch compact body context for top candidates so the agent can + // triage without extra reads in most runs. + const issueContext = scoredIssues.slice(0, MAX_ISSUES_WITH_BODY_CONTEXT).map(i => { + const body = (i.body || '').replace(/\s+/g, ' ').trim(); + const bodySnippet = body.length > BODY_SNIPPET_MAX_LENGTH ? `${body.slice(0, BODY_SNIPPET_MAX_LENGTH)}…` : body; + const labelStr = i.labels.length > 0 ? i.labels.join(', ') : 'none'; + return `#${i.number} | score=${i.score.toFixed(1)} | labels=${labelStr}\nTitle: ${i.title}\nBody: ${bodySnippet || '(no body)'}`; + }).join('\n\n---\n\n'); + const issueNumbers = scoredIssues.map(i => i.number).join(','); core.info(`Total candidate issues after filtering: ${scoredIssues.length}`); @@ -1979,6 +2012,7 @@ jobs: core.setOutput('issue_count', scoredIssues.length); core.setOutput('issue_numbers', issueNumbers); core.setOutput('issue_list', issueList); + core.setOutput('issue_context', issueContext); if (scoredIssues.length === 0) { core.info('🍽️ No suitable candidate issues - the plate is empty!'); @@ -1991,6 +2025,7 @@ jobs: core.setOutput('issue_count', 0); core.setOutput('issue_numbers', ''); core.setOutput('issue_list', ''); + core.setOutput('issue_context', ''); core.setOutput('has_issues', 'false'); } @@ -2013,7 +2048,7 @@ jobs: GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }} GH_AW_ENGINE_ID: "copilot" - GH_AW_ENGINE_MODEL: "gpt-5.1-codex-mini" + GH_AW_ENGINE_MODEL: "claude-haiku-4.5" GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e 🍪 *Om nom nom by [{workflow_name}]({run_url})*{effective_tokens_suffix}{history_link}\",\"runStarted\":\"🍪 ISSUE! ISSUE! [{workflow_name}]({run_url}) hungry for issues on this {event_type}! Om nom nom...\",\"runSuccess\":\"🍪 YUMMY! [{workflow_name}]({run_url}) ate the issues! That was DELICIOUS! Me want MORE! 😋\",\"runFailure\":\"🍪 Aww... [{workflow_name}]({run_url}) {status}. No cookie for monster today... 😢\"}" GH_AW_WORKFLOW_ID: "issue-monster" GH_AW_WORKFLOW_NAME: "Issue Monster" diff --git a/.github/workflows/issue-monster.md b/.github/workflows/issue-monster.md index bd896a1f050..88f63cc4cfc 100644 --- a/.github/workflows/issue-monster.md +++ b/.github/workflows/issue-monster.md @@ -25,6 +25,8 @@ on: with: script: | const { owner, repo } = context.repo; + const MAX_ISSUES_WITH_BODY_CONTEXT = 8; + const BODY_SNIPPET_MAX_LENGTH = 600; try { // Check for recent rate-limited PRs to avoid scheduling more work during rate limiting @@ -94,6 +96,7 @@ on: core.setOutput('issue_count', 0); core.setOutput('issue_numbers', ''); core.setOutput('issue_list', ''); + core.setOutput('issue_context', ''); core.setOutput('has_issues', 'false'); return; } @@ -330,6 +333,7 @@ on: number: issue.number, title: issue.title, labels: issue.labels.map(l => l.name), + body: issue.body, created_at: issue.created_at, score }; @@ -341,6 +345,15 @@ on: const labelStr = i.labels.length > 0 ? ` [${i.labels.join(', ')}]` : ''; return `#${i.number}: ${i.title}${labelStr} (score: ${i.score.toFixed(1)})`; }).join('\n'); + + // Pre-fetch compact body context for top candidates so the agent can + // triage without extra reads in most runs. + const issueContext = scoredIssues.slice(0, MAX_ISSUES_WITH_BODY_CONTEXT).map(i => { + const body = (i.body || '').replace(/\s+/g, ' ').trim(); + const bodySnippet = body.length > BODY_SNIPPET_MAX_LENGTH ? `${body.slice(0, BODY_SNIPPET_MAX_LENGTH)}…` : body; + const labelStr = i.labels.length > 0 ? i.labels.join(', ') : 'none'; + return `#${i.number} | score=${i.score.toFixed(1)} | labels=${labelStr}\nTitle: ${i.title}\nBody: ${bodySnippet || '(no body)'}`; + }).join('\n\n---\n\n'); const issueNumbers = scoredIssues.map(i => i.number).join(','); @@ -352,6 +365,7 @@ on: core.setOutput('issue_count', scoredIssues.length); core.setOutput('issue_numbers', issueNumbers); core.setOutput('issue_list', issueList); + core.setOutput('issue_context', issueContext); if (scoredIssues.length === 0) { core.info('🍽️ No suitable candidate issues - the plate is empty!'); @@ -364,6 +378,7 @@ on: core.setOutput('issue_count', 0); core.setOutput('issue_numbers', ''); core.setOutput('issue_list', ''); + core.setOutput('issue_context', ''); core.setOutput('has_issues', 'false'); } @@ -375,7 +390,7 @@ permissions: engine: id: copilot - model: gpt-5.1-codex-mini + model: claude-haiku-4.5 imports: - shared/github-guard-policy.md @@ -387,7 +402,7 @@ tools: mount-as-clis: true github: min-integrity: approved - toolsets: [default, pull_requests] + toolsets: [issues] if: needs.pre_activation.outputs.has_issues == 'true' @@ -397,6 +412,7 @@ jobs: issue_count: ${{ steps.search.outputs.issue_count }} issue_numbers: ${{ steps.search.outputs.issue_numbers }} issue_list: ${{ steps.search.outputs.issue_list }} + issue_context: ${{ steps.search.outputs.issue_context }} has_issues: ${{ steps.search.outputs.has_issues }} safe-outputs: @@ -473,7 +489,12 @@ Issues are scored and sorted by priority: ${{ needs.pre_activation.outputs.issue_list }} ``` -Work with this pre-fetched, filtered, and prioritized list of issues. Do not perform additional searches - the issue numbers are already identified above, sorted from highest to lowest priority. +**Pre-fetched Body Context (top candidates):** +``` +${{ needs.pre_activation.outputs.issue_context }} +``` + +Work with this pre-fetched, filtered, and prioritized list of issues. Do not perform additional searches - candidate issue numbers and body excerpts are already identified above. ### 1a. Handle Parent-Child Issue Relationships (for "task" or "plan" labeled issues) @@ -494,17 +515,7 @@ For issues with the "task" or "plan" label, check if they are sub-issues linked - Only after #101's PR is merged/closed, process #102 - This ensures orderly, sequential processing of related tasks -### 2. Review the Pre-Filtered Issue List - -The pre-activation job has already performed comprehensive filtering, including: -- Issues already assigned to Copilot -- Issues with open PRs linked to them (from any author) -- Issues with closed/merged PRs (treated as complete) -- **For "task" or "plan" labeled sub-issues**: Check if any sibling sub-issue (same parent) has an open PR from Copilot - -The list you receive has already been filtered to exclude all of these cases, so you can focus on the actual assignment logic. - -### 3. Select Up to Three Issues to Work On +### 2. Select Up to Three Issues to Work On From the prioritized and filtered list (issues WITHOUT Copilot assignments or open PRs): - **Select up to three appropriate issues** to assign @@ -538,10 +549,13 @@ From the prioritized and filtered list (issues WITHOUT Copilot assignments or op - Assign only the issues that are clearly separate in topic - Do not force assignments just to reach the maximum -### 4. Read and Understand Each Selected Issue +### 3. Validate Selected Issues (Body-First) For each selected issue (which has already been pre-filtered to ensure no open/closed PRs exist): -- Read the full issue body and any comments +- Use the pre-fetched body context first +- If a body excerpt is ambiguous, call `issue_read` with `method: get` for that issue +- Do **not** fetch comments by default +- Only fetch comments (`issue_read` with `method: get_comments`) when a specific triage rule truly requires comment context (for example: to confirm whether maintainers already requested a specific implementation approach, or to capture additional repro steps posted after the original issue body) - Understand what fix is needed - Identify the files that need to be modified - Verify it doesn't overlap with the other selected issues @@ -562,7 +576,7 @@ Some issues may be blocked by an integrity policy when you try to read them with → Call `noop` with: `"🛡️ All 3 candidates (#100, #102, #105) were integrity-filtered. No assignments made this run."` -### 5. Assign Issues to Copilot Agent +### 4. Assign Issues to Copilot Agent For each selected issue, use the `assign_to_agent` tool from the `safeoutputs` MCP server to assign the Copilot coding agent: @@ -578,7 +592,7 @@ The Copilot coding agent will: 3. Create a pull request with the fix 4. Follow the repository's AGENTS.md guidelines -### 6. Add Comment to Each Assigned Issue +### 5. Add Comment to Each Assigned Issue For each issue you assign, use the `add_comment` tool from the `safeoutputs` MCP server to add a comment: @@ -616,21 +630,11 @@ Issue Monster runs frequently (every 30 minutes), so keeping each run lean is cr ## Success Criteria A successful run means: -1. **Rate limiting check passed** - The search verified no recent PRs are rate-limited (or workflow skipped if rate limiting detected) -2. You reviewed the pre-searched, filtered, and prioritized issue list -3. The search already excluded issues with problematic labels (wontfix, question, discussion, etc.) -4. The search already excluded issues with campaign labels (campaign:*) as these are managed by campaign orchestrators -5. The search already excluded issues that already have assignees -6. The search already excluded issues that have sub-issues (parent/organizing issues are not tasks) -7. The search already excluded issues with closed or merged PRs (treated as complete) -8. The search already excluded issues with open PRs from Copilot coding agent (already being worked on) -9. Issues are sorted by priority score (good-first-issue, bug, security, etc. get higher scores) -10. For "task" or "plan" issues: You checked for parent issues and sibling sub-issue PRs if necessary -11. You selected up to three appropriate issues from the top of the priority list that are completely separate in topic -12. You read and understood each issue -13. You verified that the selected issues don't have overlapping concerns or file changes -14. You assigned each issue to the Copilot coding agent using `assign_to_agent` -15. You commented on each issue being assigned +1. You used the pre-fetched prioritized list (and body context) without re-searching +2. You selected up to three issues that are clearly separate in topic +3. You used body-first validation and only fetched comments when strictly necessary +4. You assigned each selected issue to Copilot using `assign_to_agent` +5. You commented on each assigned issue (or called `noop` when no assignments were made) ## Error Handling