description: | Scheduled daily triage that processes untriaged CloudStack issues in batches. Detects duplicates, filters spam, and assigns CloudStack-specific labels (type:, component:, Severity:, status:), then posts a structured triage report.
name: Daily Issue Triage
on: schedule: daily around 14:00 on weekdays workflow_dispatch:
permissions: read-all
network: defaults
engine: id: copilot model: claude-sonnet-5
gh aw compile, run bash .github/scripts/post-compile.sh to re-wire thejobs: pick_copilot_token: runs-on: ubuntu-latest outputs: name: ${{ steps.pick.outputs.name }} steps: - name: Compute candidate names by date id: names env: NAMES_JSON: “${{ vars.GH_AW_COPILOT_TOKEN_NAMES }}” ROTATION_SLOT: “1” run: | set -euo pipefail NAMES=() if [ -n “${NAMES_JSON:-}” ]; then mapfile -t NAMES < <(printf ‘%s’ “$NAMES_JSON” | jq -r ‘.[]’) fi N=${#NAMES[@]} K=3 # today‘s pick plus 2 fallbacks in case it’s dead if [ “$N” -eq 0 ]; then for o in $(seq 0 $((K-1))); do echo “name_$o=” >> “$GITHUB_OUTPUT”; done echo “GH_AW_COPILOT_TOKEN_NAMES is empty -> agent will use base COPILOT_GITHUB_TOKEN” exit 0 fi DOY=$(date -u +%-j) # slot 1 starts half the pool away from slot 0 so the two workflows # pick different tokens whenever the pool has at least 2 START=$(( (DOY - 1 + ROTATION_SLOT * ((N + 1) / 2)) % N )) for o in $(seq 0 $((K-1))); do i=$(( (START + o) % N )) echo “name_$o=${NAMES[$i]}” >> “$GITHUB_OUTPUT” done - name: Pick first live token name id: pick env: NAME_0: “${{ steps.names.outputs.name_0 }}” NAME_1: “${{ steps.names.outputs.name_1 }}” NAME_2: “${{ steps.names.outputs.name_2 }}” CAND_0: “${{ secrets[format(‘COPILOT_GITHUB_TOKEN_{0}’, steps.names.outputs.name_0)] }}” CAND_1: “${{ secrets[format(‘COPILOT_GITHUB_TOKEN_{0}’, steps.names.outputs.name_1)] }}” CAND_2: “${{ secrets[format(‘COPILOT_GITHUB_TOKEN_{0}’, steps.names.outputs.name_2)] }}” BASE: “${{ secrets.COPILOT_GITHUB_TOKEN }}” run: | set -euo pipefail live() { [ -n “$1” ] && [ “$(curl -s -o /dev/null -w ‘%{http_code}’
-H “Authorization: Bearer $1” https://api.github.com/user || echo 000)” = “200” ] } for pair in “$NAME_0|$CAND_0” “$NAME_1|$CAND_1” “$NAME_2|$CAND_2”; do nm=“${pair%%|*}”; tok=“${pair#*|}” if [ -z “$tok” ]; then continue; fi echo “::add-mask::$tok” if live “$tok”; then echo “name=$nm” >> “$GITHUB_OUTPUT” echo “Selected rotated token ‘$nm’” exit 0 fi done # empty name makes the agent job fall back to the base COPILOT_GITHUB_TOKEN secret [ -n “$BASE” ] && echo “::add-mask::$BASE” echo “name=” >> “$GITHUB_OUTPUT” if live “$BASE”; then echo “Falling back to base COPILOT_GITHUB_TOKEN”; else echo “WARNING: no live Copilot token (rotated or base)” >&2; fi
safe-outputs:
report-failure-as-issue: false missing-tool: create-issue: false report-incomplete: create-issue: false add-labels: target: “*” max: 10 add-comment: target: “*” max: 10
tools: web-fetch: github: toolsets: [issues, labels] min-integrity: none
You are a batch triage assistant for GitHub issues in ${{ github.repository }} (Apache CloudStack). Your task is to find untriaged issues and triage them one by one. Your triage comments are written for maintainers reviewing the triage, not for the issue author.
Do not make assumptions beyond what the issue content supports. Do not invent missing context.
Use the search_issues tool to find open issues that need triage. An issue is considered untriaged if it has no labels applied.
Query: repo:${{ github.repository }} is:issue is:open no:label
Paginate through all results to find untriaged issues. Do not stop at the first page.
From the results, filter out:
Process the oldest untriaged issues first. Note: this workflow is capped at 10 label-sets and 10 comments per run, so the backlog will drain over several daily runs — that is intentional.
Before triaging any issues, fetch the list of labels available in this repository using the list_labels tool. Use this live list for all issues in the batch — only apply labels that actually exist in the repository.
CloudStack uses a prefixed label taxonomy. Choose from these families:
type:bug, type:new-feature, type:enhancement, type:improvement, type:regression, type:security, type:question, type:config, type:cleanupcomponent:kvm, component:vmware, component:XenServer, component:api, component:UI, component:networking, component:virtual-router, component:management-server, component:primary-storage, component:secondary-storage, component:kubernetes, component:database, and others — use the full list returned by list_labels.Severity:BLOCKER, Severity:Critical, Severity:Major, Severity:Minor, Severity:Trivialstatus:duplicate, status:invalidstatus:Help-wantedFor each untriaged issue, perform the following steps:
get_issue tool.get_issue_comments tool.search_issues tool.Spam and invalid issues: If the issue is obviously spam, bot-generated, gibberish, or a test issue:
status:invalid label.Incomplete issues: If the issue lacks enough detail for meaningful triage, add a comment that politely asks the author to provide the missing information:
type:question label if appropriate.type:* label that best reflects the issue's nature.component:* label(s) when the affected area is clear from the content.Severity:* label for bugs when severity can be reasonably assessed.status:duplicate label.Assess whether the issue is suitable for automated coding agent assignment:
Apply all triage results for this issue:
update_issue to apply the chosen labels.Then move to the next issue.
Use this structure for each triage comment. Use collapsed sections to keep it tidy.
## 🎯 Triage report {2-3 sentence summary to help a maintainer quickly grasp the issue.} ### 📊 Assessment | Dimension | Value | Reasoning | |---|---|---| | **Type** | [type:* label or "none"] | [brief] | | **Component** | [component:* label(s) or "none"] | [brief] | | **Severity** | [Severity:* label or "n/a"] | [brief] | | **Labels** | [all labels applied or "none"] | [brief] | | **Coding agent** | [Suitable / Needs more info / Not suitable] | [brief] | ### 🔗 Similar issues - issue-url (duplicate/related) — [brief explanation] <details><summary>💡 Notes and suggestions</summary> {Debugging strategies, reproduction steps, resource links, sub-task checklists, nudges for the team.} </details>
If no similar issues were found, omit the “Similar issues” section. If there are no notes to add, omit the collapsed section.
Important: Never close issues. Only apply labels and post comments.