Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
562defc
feat(examples): add automated issue cleanup workflow
cocosheng-g Apr 6, 2026
69bd8f0
fix(lint): YAML quoting in issue cleanup workflow
cocosheng-g Apr 6, 2026
a416cf5
feat(examples): optimize issue cleanup prompt for efficiency
cocosheng-g Apr 6, 2026
0d94b4b
feat(examples): instruct agent to explicitly clone the target repository
cocosheng-g Apr 6, 2026
0eedc99
fix(examples): apply PR review suggestions for issue cleanup workflow
cocosheng-g Apr 6, 2026
298d9d6
feat(examples): allow custom instructions for issue cleanup triage su…
cocosheng-g Apr 6, 2026
cf62bef
feat(examples): support fallback to standard triage summary if custom…
cocosheng-g Apr 6, 2026
1cdeb18
feat(examples): add staleness check and optimize cleanup bot
cocosheng-g Apr 6, 2026
225eca7
feat(examples): separate staleness check from agent via github-script
cocosheng-g Apr 6, 2026
6cee6e8
feat(examples): support explicit maintainers input for staleness check
cocosheng-g Apr 6, 2026
3652158
fix(examples): fix YAML syntax error for MAINTAINERS environment vari…
cocosheng-g Apr 6, 2026
d572273
feat(examples): enable AI to write and execute reproduction scripts t…
cocosheng-g Apr 6, 2026
d0904f5
feat(examples): add 1-month age check for issue cleanup
cocosheng-g Apr 6, 2026
2b10d1f
feat(examples): ask for detailed reproduction steps in 1-month age check
cocosheng-g Apr 6, 2026
55bf172
feat(examples): move 1-month age check to native github-script step
cocosheng-g Apr 6, 2026
67c9554
fix(examples): expand staleness maintainer check to include repositor…
cocosheng-g Apr 6, 2026
7892be4
feat(examples): update issue labels during staleness and inactivity c…
cocosheng-g Apr 6, 2026
fa2f699
fix(examples): only update labels when asking for repro, not when clo…
cocosheng-g Apr 6, 2026
7817cb2
feat(examples): close issue when asking for repro after 1 month inact…
cocosheng-g Apr 6, 2026
0345f07
feat(examples): instruct reporter to reopen issue if reproducible in …
cocosheng-g Apr 6, 2026
d966b7f
feat(examples): close stale and inactive issues as 'not planned'
cocosheng-g Apr 6, 2026
fc993bb
fix(examples): quote 'on' in workflow yaml to satisfy yamllint truthy…
cocosheng-g Apr 6, 2026
a5f1f4e
feat(examples): exempt P0/P1 issues from auto-closing and tag assignees
cocosheng-g Apr 6, 2026
d1c7784
feat(examples): customize 30-day inactivity comment for feature requests
cocosheng-g Apr 6, 2026
8867a8c
feat(examples): skip triage for issues tracked by epics or projects
cocosheng-g Apr 6, 2026
afec57e
feat(examples): ask reporter for clarification on unassigned feature …
cocosheng-g Apr 7, 2026
017c077
feat(examples): ask for repro on tracked non-feature issues with no a…
cocosheng-g Apr 7, 2026
3d7b3cd
feat(examples): check for resolved comments before asking for repro, …
cocosheng-g Apr 7, 2026
7b58e43
feat(examples): let AI agent analyze comments to identify resolved is…
cocosheng-g Apr 7, 2026
b5e9a4f
feat(examples): refactor triage prompt to action-first syntax to stop…
cocosheng-g Apr 7, 2026
399fae8
fix(examples): force triage bot to serialize setup operations and blo…
cocosheng-g Apr 7, 2026
ced7de3
feat(workflows): refactor issue cleanup to use single source of truth…
cocosheng-g Apr 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/commands/gemini-issue-cleanup.toml
25 changes: 25 additions & 0 deletions examples/workflows/issue-cleanup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Issue Cleanup Workflow

This document describes a workflow to batch-process and clean up older open issues using Gemini CLI.

## Overview

The Issue Cleanup workflow is designed to automate the triage of stale issues by using the Gemini CLI to:

1. **Check for Parent Issues (Native)**: Identifies if an issue is tracked by a parent issue (task list). If so, it removes the triage label and stops, assuming the issue is already being managed as part of a larger epic. If it has no assignees, it additionally asks the reporter if it is still needed (for feature requests) or asks them to try reproducing it with the latest build (for other issues).
2. **Check for Staleness and Age (Native)**: Identifies if an issue has been waiting for reporter feedback for over 7 days, closing it if so. If the issue is not stale but hasn't been updated in over a month, it first checks if the last comment indicates the issue is resolved (e.g., "functioning properly"); if so, it closes it as completed. Otherwise, it asks the reporter to reproduce it with the latest build. For feature requests, it asks to reopen if still needed. By default, it closes the inactive issue as "not planned" and tags any assignees to reopen it. However, if the issue is a high-priority (`p0` or `p1`), it leaves the issue open. This logic runs natively to save AI resources.
3. **Check for Vagueness (AI)**: If an issue is not stale or old but lacks sufficient information (e.g., reproduction steps), the agent asks the reporter for specific details and stops.
4. **Check Code Validity (AI)**: Determines if an issue is still relevant against the current codebase. The agent may attempt to write and execute a minimal reproduction script to verify if a bug has been resolved, or manually inspect the code. If verified as fixed, it will close the issue with an explanation.
5. **Find Duplicates (AI)**: Checks if the issue has a more recent duplicate. If a duplicate exists, it closes the issue and links to the duplicate.
6. **Summarize for Triage (AI)**: If an issue is still valid and unique, it provides a summary comment based on customizable instructions (e.g., categorizing it as `Maintainer-only` or `Help-wanted`). If no custom instructions are provided, it falls back to a standard triage summary.

## Usage

This example is tailored to process issues in your repository matching specific labels (`area/core`, `area/extensions`, `area/site`, `area/non-interactive`), selecting the 10 issues with the oldest last update time.

To adapt this to your own repository:

1. Copy `gemini-issue-cleanup.yml` to your repository's `.github/workflows/` directory.
2. Update the search string in the `Find old issues for cleanup` step in `gemini-issue-cleanup.yml` to match your repository's labels.
3. Configure the `maintainers` input in `gemini-issue-cleanup.yml` (either via the workflow dispatch inputs or by setting the `MAINTAINERS` repository variable) to explicitly list which users count as maintainers for the staleness check.
4. Copy `gemini-issue-cleanup.toml` to your `.github/commands/` directory.
85 changes: 85 additions & 0 deletions examples/workflows/issue-cleanup/gemini-issue-cleanup.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
description = "Analyzes and cleans up older issues by checking code validity, duplicates, and providing a triage summary."
prompt = """
Execute the following triage process for `!{echo $ISSUE_LINK}`.
You are a script executor. You MUST execute these steps in exact sequential order. Do not skip steps. Do not parallelize steps. Do not investigate your own configuration. DO NOT clone the repository until you reach Step 5.

<custom_instructions>
!{echo $CUSTOM_INSTRUCTIONS}
</custom_instructions>

### STEP 1: FETCH DATA (MANDATORY FIRST TURN)
You MUST execute ONLY these commands in your very first turn. Do NOT execute any other tools.
1. `gh issue view !{echo $ISSUE_LINK} --json title,body,author,comments,labels,assignees`
2. `gh api repos/!{echo $REPOSITORY}/issues/$(echo !{echo $ISSUE_LINK} | awk -F/ '{print $NF}')/timeline --jq '[.[] | select(.event == "cross-referenced" and .source.issue)] | map({issue: .source.issue.number, state: .source.issue.state, state_reason: .source.issue.state_reason, is_pr: (.source.issue.pull_request != null)})'`
3. `gh api graphql -F owner=$(echo !{echo $REPOSITORY} | cut -d/ -f1) -F repo=$(echo !{echo $REPOSITORY} | cut -d/ -f2) -F number=$(echo !{echo $ISSUE_LINK} | awk -F/ '{print $NF}') -f query='query($owner: String!, $repo: String!, $number: Int!) { repository(owner: $owner, name: $repo) { issue(number: $number) { parent { number } } } }' --jq '.data.repository.issue.parent'`
4. `gh api repos/!{echo $REPOSITORY}/issues/$(echo !{echo $ISSUE_LINK} | awk -F/ '{print $NF}') --jq '{is_epic: (.sub_issues_summary.total > 0)}'`

WAIT for the outputs of Step 1 before proceeding to Step 2.

### STEP 2: PRE-TRIAGE OVERRIDES
Review the <custom_instructions> provided at the beginning of this prompt. Do they contain any conditions that dictate stopping execution early based on the data fetched in Step 1 (e.g., specific labels)?
- If YES and the condition is met: Execute the actions specified in the custom instructions and **STOP EXECUTION IMMEDIATELY**. Do not proceed to Step 3.
- If NO or the condition is not met: Proceed to Step 3.

### STEP 3: RESOLUTION CHECK
Read ALL the comments from the `gh issue view` output carefully.
Check if ANY of the following conditions are met in the comments (especially the latest ones):
1. Is it fixed, resolved, no longer reproducible, or functioning properly? (e.g., someone mentions it `might be fixed`, `should be fixed`, or `no longer an issue`) AND the reporter has not replied afterward to contradict this?
2. Is there a workaround provided?
3. Does someone state the issue is actually unrelated to this repository/project, or is an external problem (like a terminal emulator bug)?

- If condition 1 or 2 is met: Execute `gh issue close !{echo $ISSUE_LINK} --comment "Closing because the comments indicate this issue might be fixed, has a workaround, is no longer an issue, or is resolved. Feel free to reopen if the problem persists." --reason "completed"` and **STOP EXECUTION IMMEDIATELY**.
- If condition 3 is met: Execute `gh issue close !{echo $ISSUE_LINK} --comment "Closing because the comments indicate this issue is unrelated to the Gemini CLI or is an external problem." --reason "not planned"` and **STOP EXECUTION IMMEDIATELY**.
- If NONE of these conditions are met: Proceed to Step 4.

### STEP 4: ASSIGNEE AND INACTIVITY CHECK
1. ASSIGNEE CHECK: Look at the assignees and comments from Step 1. If an assignee is a contributor and hasn't made any updates on the issue for over 2 weeks, you MUST execute `gh issue edit !{echo $ISSUE_LINK} --remove-assignee <username>` to remove them. (Do this before proceeding further).
2. INACTIVITY CHECK: Check the environment variable `!{echo $INACTIVE_OVER_60_DAYS}`. Is it exactly equal to the string `true`?
- If YES:
a. Formulate a comment to the reporter (@<reporter_username>). Evaluate the issue description and whether it is an Epic (from Step 1.4):
- Always mention that the issue is being closed or pinged because it has been inactive for over 60 days.
- IF IT IS AN EPIC (has sub-issues): Ask the reporter if it is still in progress or complete, and if it is complete, ask them to close it.
- IF IT IS NOT AN EPIC:
- If it's a feature/enhancement request and the description is relatively vague, ask: 1) if it is still needed and 2) if they can provide more details on the feature request.
- If the issue was mentioned by another issue that is closed as completed or by a pull request that is merged/closed (based on the cross-referenced timeline events), mention this cross-reference (e.g., "I see this issue was mentioned by #123 which is closed as completed...") and ask if this means it is resolved. Do NOT mention cross-references that are still open or closed as "not planned".
- If it's a feature/enhancement request but well-described, just ask if it's still needed.
- If it's a bug, ask if they can reproduce it with the latest build and provide detailed reproduction steps.
- If the issue has assignees, append a ping to the assignees to check in.
- If it is NOT an Epic AND the issue is NOT high priority (`priority/p0` or `priority/p1`) AND does NOT have a parent issue (from Step 1.3), append "Feel free to reopen this issue." to the comment.
b. Execute `gh issue edit !{echo $ISSUE_LINK} --remove-label "status/need-triage"` (ignore errors if the label doesn't exist). If it is NOT an Epic, also append `--add-label "status/needs-info"`.
c. Execute `gh issue comment !{echo $ISSUE_LINK} --body "<your formulated comment>"`
d. If it is NOT an Epic AND the issue is NOT high priority AND does NOT have a parent issue (from Step 1.3), execute `gh issue close !{echo $ISSUE_LINK} --reason "not planned"`.
- After executing these actions, **STOP EXECUTION IMMEDIATELY**. Do not proceed to Step 5.
- If NO: Check the environment variable `!{echo $INACTIVE_OVER_30_DAYS}`. Is it exactly equal to the string `true`?
- If YES AND the issue is a bug report (not a feature/enhancement request) AND it is NOT an Epic:
a. Execute `gh issue edit !{echo $ISSUE_LINK} --remove-label "status/need-triage" --add-label "status/needs-info"` (ignore errors if labels don't exist).
b. Execute `gh issue comment !{echo $ISSUE_LINK} --body "@<reporter_username>, this issue has been inactive for over a month. Could you please try reproducing it with the latest nightly build and let us know if it still occurs?"`
- After executing these actions, **STOP EXECUTION IMMEDIATELY**. Do not proceed to Step 5.
- If NO (or it is not a bug, or it is an Epic): Proceed to Step 5.

### STEP 5: VAGUENESS CHECK
Is the issue fundamentally missing context AND no one has asked for more information yet?
- For bugs: Explicit reproduction steps are **REQUIRED**. Even if the user provides logs, error traces, or screenshots, if they do not provide clear, step-by-step instructions on how to reproduce the bug, it MUST be considered vague.
- For feature requests: If it is just a vague statement without clear use cases or details, it is considered vague.
- If YES (it is vague): Execute `gh issue edit !{echo $ISSUE_LINK} --remove-label "status/need-triage" --add-label "status/needs-info"` (ignore errors if labels don't exist). Ask the reporter: `gh issue comment !{echo $ISSUE_LINK} --body "@<reporter_username>, thank you for the report! Could you please provide more specific details (e.g., detailed reproduction steps, expected behavior, logs, and environment details)? Closing this as vague if no response is received in a week."` and **STOP EXECUTION IMMEDIATELY**.
- If NO: Proceed to Step 6.

### STEP 6: REPRODUCTION & CODE VALIDITY
1. Review the issue comments. If a community member has already clearly identified the root cause of the bug, DO NOT clone the repo, DO NOT write tests, and DO NOT execute any code. You may only perform a quick `grep_search` or `read_file` if the repo is already cloned to determine if the fix is simple.
- If your quick code check reveals that the problematic code has already been significantly changed or appears fixed in the current `target-repo`, DO NOT investigate git history or releases. Simply execute `gh issue edit !{echo $ISSUE_LINK} --remove-label "status/need-triage" --add-label "status/needs-info"` and `gh issue comment !{echo $ISSUE_LINK} --body "@<reporter_username>, the code related to this issue appears to have been updated recently. Could you please try reproducing it with the latest nightly build and let us know if it still occurs?"` and **STOP EXECUTION IMMEDIATELY**.
- Otherwise, immediately proceed to Step 7.
2. If no root cause is identified, run `git clone https://github.com/!{echo $REPOSITORY}.git target-repo` and search the `target-repo/` codebase using `grep_search` and `read_file` ONLY. You are explicitly FORBIDDEN from writing new files, running `npm test`, attempting to fix the code, OR attempting to reproduce the bug by executing code or shell commands (e.g., creating named pipes, running scripts, etc.). Your ONLY goal is to perform STATIC code analysis to determine if the logic for the bug still exists, if the feature is already implemented, or if the reported behavior is actually intentional by design.
- If definitively NO LONGER VALID: Close it: `gh issue close !{echo $ISSUE_LINK} --comment "Closing because I have verified this works correctly in the latest codebase. <brief explanation>"` and **STOP EXECUTION IMMEDIATELY**.
- If INTENTIONAL BY DESIGN: Close it: `gh issue close !{echo $ISSUE_LINK} --reason "not planned" --comment "Closing this issue as the reported behavior is intentional by design. <brief explanation of the design logic>"` and **STOP EXECUTION IMMEDIATELY**.
- If still valid: Proceed to Step 7.

### STEP 7: DUPLICATES
Search for duplicates using `gh issue list --search "<keywords>" --repo !{echo $REPOSITORY} --state all`.
- If found: `gh issue close !{echo $ISSUE_LINK} --reason "not planned" --comment "Closing as duplicate of #<duplicate_number>."` and **STOP EXECUTION IMMEDIATELY**.
- If no duplicates: Proceed to Step 8.

### STEP 8: TRIAGE SUMMARY
Provide a summary comment using the <custom_instructions> provided at the beginning of this prompt.
- Action: `gh issue comment !{echo $ISSUE_LINK} --body "### Triage Summary\\n\\n<your summary>"`
- **STOP EXECUTION**.
"""
Loading
Loading