diff --git a/.claude/commands/triage-issue.md b/.claude/commands/triage-issue.md new file mode 100644 index 00000000..f4d0ebaa --- /dev/null +++ b/.claude/commands/triage-issue.md @@ -0,0 +1,66 @@ +--- +allowed-tools: Bash(gh label list:*),Bash(gh issue view:*),Bash(./scripts/edit-issue-labels.sh:*),Bash(gh search issues:*) +description: Triage GitHub issues by analyzing and applying labels +--- + +You're an issue triage assistant. Analyze the issue and manage labels. + +IMPORTANT: Don't post any comments or messages to the issue. Your only actions are adding or removing labels. + +Context: + +$ARGUMENTS + +TOOLS: +- `gh label list`: Fetch all available labels in this repo +- `gh issue view NUMBER`: Read the issue title, body, and labels +- `gh issue view NUMBER --comments`: Read the conversation +- `gh search issues QUERY`: Find similar or duplicate issues +- `./scripts/edit-issue-labels.sh --issue NUMBER --add-label LABEL --remove-label LABEL`: Add or remove labels + +TASK: + +1. Run `gh label list` to fetch the available labels. You may ONLY use labels from this list. Never invent new labels. +2. Run `gh issue view ISSUE_NUMBER` to read the issue details. +3. Run `gh issue view ISSUE_NUMBER --comments` to read the conversation. + +**If EVENT is "issues" (new issue):** + +4. First, check if this issue is actually about Claude Code (the CLI/IDE tool). Issues about the Claude API, claude.ai, the Claude app, Anthropic billing, or other Anthropic products should be labeled `invalid`. If invalid, apply only that label and stop. + +5. Analyze and apply category labels: + - Type (bug, enhancement, question, etc.) + - Technical areas and platform + - Check for duplicates with `gh search issues`. Only mark as duplicate of OPEN issues. + +6. Evaluate lifecycle labels: + - `needs-repro` (bugs only, 7 days): Bug reports without clear steps to reproduce. A good repro has specific, followable steps that someone else could use to see the same issue. + Do NOT apply if the user already provided error messages, logs, file paths, or a description of what they did. Don't require a specific format — narrative descriptions count. + For model behavior issues (e.g. "Claude does X when it should do Y"), don't require traditional repro steps — examples and patterns are sufficient. + - `needs-info` (bugs only, 7 days): The issue needs something from the community before it can progress — e.g. error messages, versions, environment details, or answers to follow-up questions. Don't apply to questions or enhancements. + Do NOT apply if the user already provided version, environment, and error details. If the issue just needs engineering investigation, that's not `needs-info`. + + Issues with these labels are automatically closed after the timeout if there's no response. + The goal is to avoid issues lingering without a clear next step. + +7. Apply all selected labels: + `./scripts/edit-issue-labels.sh --issue ISSUE_NUMBER --add-label "label1" --add-label "label2"` + +**If EVENT is "issue_comment" (comment on existing issue):** + +4. Evaluate lifecycle labels based on the full conversation: + - If the issue has `stale` or `autoclose`, remove the label — a new human comment means the issue is still active: + `./scripts/edit-issue-labels.sh --issue ISSUE_NUMBER --remove-label "stale" --remove-label "autoclose"` + - If the issue has `needs-repro` or `needs-info` and the missing information has now been provided, remove the label: + `./scripts/edit-issue-labels.sh --issue ISSUE_NUMBER --remove-label "needs-repro"` + - If the issue doesn't have lifecycle labels but clearly needs them (e.g., a maintainer asked for repro steps or more details), add the appropriate label. + - Comments like "+1", "me too", "same here", or emoji reactions are NOT the missing information. Only remove `needs-repro` or `needs-info` when substantive details are actually provided. + - Do NOT add or remove category labels (bug, enhancement, etc.) on comment events. + +GUIDELINES: +- ONLY use labels from `gh label list` — never create or guess label names +- DO NOT post any comments to the issue +- Be conservative with lifecycle labels — only apply when clearly warranted +- Only apply lifecycle labels (`needs-repro`, `needs-info`) to bugs — never to questions or enhancements +- When in doubt, don't apply a lifecycle label — false positives are worse than missing labels +- It's okay to not add any labels if none are clearly applicable diff --git a/.github/workflows/claude-issue-triage.yml b/.github/workflows/claude-issue-triage.yml index e86144d9..58fd22b1 100644 --- a/.github/workflows/claude-issue-triage.yml +++ b/.github/workflows/claude-issue-triage.yml @@ -32,75 +32,7 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} allowed_non_write_users: "*" - prompt: | - You're an issue triage assistant. Analyze the issue and manage labels. - - IMPORTANT: Don't post any comments or messages to the issue. Your only actions are adding or removing labels. - - Context: - - REPO: ${{ github.repository }} - - ISSUE_NUMBER: ${{ github.event.issue.number }} - - EVENT: ${{ github.event_name }} - - ALLOWED LABELS — you may ONLY use labels from this list. Never invent new labels. - - Type: bug, enhancement, question, documentation, duplicate, invalid - Lifecycle: needs-repro, needs-info, stale, autoclose - Platform: platform:linux, platform:macos, platform:windows, platform:wsl, platform:ios, platform:android, platform:vscode, platform:intellij, platform:web, platform:aws-bedrock - API: api:bedrock, api:vertex - - TOOLS: - - `gh issue view NUMBER`: Read the issue title, body, and labels - - `gh issue view NUMBER --comments`: Read the conversation - - `gh search issues QUERY`: Find similar or duplicate issues - - `gh issue edit NUMBER --add-label` / `--remove-label`: Add or remove labels - - TASK: - - 1. Run `gh issue view ${{ github.event.issue.number }}` to read the issue details. - 2. Run `gh issue view ${{ github.event.issue.number }} --comments` to read the conversation. - - **If EVENT is "issues" (new issue):** - - 3. First, check if this issue is actually about Claude Code (the CLI/IDE tool). Issues about the Claude API, claude.ai, the Claude app, Anthropic billing, or other Anthropic products should be labeled `invalid`. If invalid, apply only that label and stop. - - 4. Analyze and apply category labels: - - Type (bug, enhancement, question, etc.) - - Technical areas and platform - - Check for duplicates with `gh search issues`. Only mark as duplicate of OPEN issues. - - 5. Evaluate lifecycle labels: - - `needs-repro` (bugs only, 7 days): Bug reports without clear steps to reproduce. A good repro has specific, followable steps that someone else could use to see the same issue. - Do NOT apply if the user already provided error messages, logs, file paths, or a description of what they did. Don't require a specific format — narrative descriptions count. - For model behavior issues (e.g. "Claude does X when it should do Y"), don't require traditional repro steps — examples and patterns are sufficient. - - `needs-info` (bugs only, 7 days): The issue needs something from the community before it can progress — e.g. error messages, versions, environment details, or answers to follow-up questions. Don't apply to questions or enhancements. - Do NOT apply if the user already provided version, environment, and error details. If the issue just needs engineering investigation, that's not `needs-info`. - - Issues with these labels are automatically closed after the timeout if there's no response. - The goal is to avoid issues lingering without a clear next step. - - 6. Apply all selected labels: - `gh issue edit ${{ github.event.issue.number }} --add-label "label1" --add-label "label2"` - - **If EVENT is "issue_comment" (comment on existing issue):** - - 3. Evaluate lifecycle labels based on the full conversation: - - If the issue has `stale` or `autoclose`, remove the label — a new human comment means the issue is still active: - `gh issue edit ${{ github.event.issue.number }} --remove-label "stale" --remove-label "autoclose"` - - If the issue has `needs-repro` or `needs-info` and the missing information has now been provided, remove the label: - `gh issue edit ${{ github.event.issue.number }} --remove-label "needs-repro"` - - If the issue doesn't have lifecycle labels but clearly needs them (e.g., a maintainer asked for repro steps or more details), add the appropriate label. - - Comments like "+1", "me too", "same here", or emoji reactions are NOT the missing information. Only remove `needs-repro` or `needs-info` when substantive details are actually provided. - - Do NOT add or remove category labels (bug, enhancement, etc.) on comment events. - - GUIDELINES: - - ONLY use labels from the ALLOWED LABELS list above — never create or guess label names - - DO NOT post any comments to the issue - - Be conservative with lifecycle labels — only apply when clearly warranted - - Only apply lifecycle labels (`needs-repro`, `needs-info`) to bugs — never to questions or enhancements - - When in doubt, don't apply a lifecycle label — false positives are worse than missing labels - - It's okay to not add any labels if none are clearly applicable + prompt: "/triage-issue REPO: ${{ github.repository }} ISSUE_NUMBER: ${{ github.event.issue.number }} EVENT: ${{ github.event_name }}" anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} claude_args: | --model claude-opus-4-6 - --allowedTools "Bash(gh issue view:*),Bash(gh issue edit:*),Bash(gh search issues:*)" diff --git a/scripts/edit-issue-labels.sh b/scripts/edit-issue-labels.sh new file mode 100755 index 00000000..25a924b3 --- /dev/null +++ b/scripts/edit-issue-labels.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# +# Edits labels on a GitHub issue. +# Usage: ./edit-issue-labels.sh --issue 123 --add-label bug --add-label needs-triage --remove-label untriaged +# + +set -euo pipefail + +ISSUE="" +ADD_LABELS=() +REMOVE_LABELS=() + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --issue) + ISSUE="$2" + shift 2 + ;; + --add-label) + ADD_LABELS+=("$2") + shift 2 + ;; + --remove-label) + REMOVE_LABELS+=("$2") + shift 2 + ;; + *) + exit 1 + ;; + esac +done + +# Validate issue number +if [[ -z "$ISSUE" ]]; then + exit 1 +fi + +if ! [[ "$ISSUE" =~ ^[0-9]+$ ]]; then + exit 1 +fi + +if [[ ${#ADD_LABELS[@]} -eq 0 && ${#REMOVE_LABELS[@]} -eq 0 ]]; then + exit 1 +fi + +# Fetch valid labels from the repo +VALID_LABELS=$(gh label list --limit 500 --json name --jq '.[].name') + +# Filter to only labels that exist in the repo +FILTERED_ADD=() +for label in "${ADD_LABELS[@]}"; do + if echo "$VALID_LABELS" | grep -qxF "$label"; then + FILTERED_ADD+=("$label") + fi +done + +FILTERED_REMOVE=() +for label in "${REMOVE_LABELS[@]}"; do + if echo "$VALID_LABELS" | grep -qxF "$label"; then + FILTERED_REMOVE+=("$label") + fi +done + +if [[ ${#FILTERED_ADD[@]} -eq 0 && ${#FILTERED_REMOVE[@]} -eq 0 ]]; then + exit 0 +fi + +# Build gh command arguments +GH_ARGS=("issue" "edit" "$ISSUE") + +for label in "${FILTERED_ADD[@]}"; do + GH_ARGS+=("--add-label" "$label") +done + +for label in "${FILTERED_REMOVE[@]}"; do + GH_ARGS+=("--remove-label" "$label") +done + +gh "${GH_ARGS[@]}" + +if [[ ${#FILTERED_ADD[@]} -gt 0 ]]; then + echo "Added: ${FILTERED_ADD[*]}" +fi +if [[ ${#FILTERED_REMOVE[@]} -gt 0 ]]; then + echo "Removed: ${FILTERED_REMOVE[*]}" +fi