Compare commits

..

7 Commits

Author SHA1 Message Date
Octavian Guzu
cebbc4f721 Use gh.sh wrapper for all gh commands in triage and dedupe workflows 2026-02-25 13:43:36 +00:00
Octavian Guzu
3c917dfe50 Add non-write users check workflow 2026-02-24 18:09:41 +00:00
GitHub Actions
8f0fe03e56 chore: Update CHANGELOG.md 2026-02-24 06:39:08 +00:00
GitHub Actions
baf29b882a chore: Update CHANGELOG.md 2026-02-24 02:04:23 +00:00
GitHub Actions
6aecb15d98 chore: Update CHANGELOG.md 2026-02-24 01:40:09 +00:00
Octavian Guzu
76826f2c80 Merge pull request #27911 from anthropics/oct/use-label-script-for-triage
Use wrapper script for label operations in issue triage
2026-02-23 20:07:02 +00:00
Octavian Guzu
3592c8be2a Use wrapper script for label operations in issue triage
Extract triage prompt into /triage-issue command and use a dedicated
edit-issue-labels.sh script for label operations instead of raw
gh issue edit. The script validates labels against the repo's existing
labels before applying them.
2026-02-23 15:11:01 +00:00
7 changed files with 272 additions and 72 deletions

View File

@@ -1,5 +1,5 @@
---
allowed-tools: Bash(gh issue view:*), Bash(gh search:*), Bash(gh issue list:*), Bash(./scripts/comment-on-duplicates.sh:*)
allowed-tools: Bash(./scripts/gh.sh:*), Bash(./scripts/comment-on-duplicates.sh:*)
description: Find duplicate GitHub issues
---
@@ -18,6 +18,10 @@ To do this, follow these steps precisely:
Notes (be sure to tell this to your agents, too):
- Use `gh` to interact with Github, rather than web fetch
- Do not use other tools, beyond `gh` and the comment script (eg. don't use other MCP servers, file edit, etc.)
- Use `./scripts/gh.sh` to interact with Github, rather than web fetch or raw `gh`. Examples:
- `./scripts/gh.sh issue view 123` — view an issue
- `./scripts/gh.sh issue view 123 --comments` — view with comments
- `./scripts/gh.sh issue list --state open --limit 20` — list issues
- `./scripts/gh.sh search issues "query" --limit 10` — search for issues
- Do not use other tools, beyond `./scripts/gh.sh` and the comment script (eg. don't use other MCP servers, file edit, etc.)
- Make a todo list first

View File

@@ -0,0 +1,70 @@
---
allowed-tools: Bash(./scripts/gh.sh:*),Bash(./scripts/edit-issue-labels.sh:*)
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:
- `./scripts/gh.sh` — wrapper for `gh` CLI. Only supports these subcommands and flags:
- `./scripts/gh.sh label list` — fetch all available labels
- `./scripts/gh.sh label list --limit 100` — fetch with limit
- `./scripts/gh.sh issue view 123` — read issue title, body, and labels
- `./scripts/gh.sh issue view 123 --comments` — read the conversation
- `./scripts/gh.sh issue list --state open --limit 20` — list issues
- `./scripts/gh.sh search issues "query"` — find similar or duplicate issues
- `./scripts/gh.sh search issues "query" --limit 10` — search with limit
- `./scripts/edit-issue-labels.sh --issue NUMBER --add-label LABEL --remove-label LABEL` — add or remove labels
TASK:
1. Run `./scripts/gh.sh label list` to fetch the available labels. You may ONLY use labels from this list. Never invent new labels.
2. Run `./scripts/gh.sh issue view ISSUE_NUMBER` to read the issue details.
3. Run `./scripts/gh.sh 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 `./scripts/gh.sh 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 `./scripts/gh.sh 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

View File

@@ -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:*)"

View File

@@ -0,0 +1,47 @@
name: Non-write Users Check
on:
pull_request:
paths:
- ".github/**"
permissions:
contents: read
pull-requests: write
jobs:
allowed-non-write-check:
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- run: |
DIFF=$(gh pr diff "$PR_NUMBER" -R "$REPO" || true)
if ! echo "$DIFF" | grep -qE '^diff --git a/\.github/.*\.ya?ml'; then
exit 0
fi
MATCHES=$(echo "$DIFF" | grep "^+.*allowed_non_write_users" || true)
if [ -z "$MATCHES" ]; then
exit 0
fi
EXISTING=$(gh pr view "$PR_NUMBER" -R "$REPO" --json comments --jq '.comments[].body' \
| grep -c "<!-- non-write-users-check -->" || true)
if [ "$EXISTING" -gt 0 ]; then
exit 0
fi
gh pr comment "$PR_NUMBER" -R "$REPO" --body '<!-- non-write-users-check -->
**`allowed_non_write_users` detected**
This PR adds or modifies `allowed_non_write_users`, which allows users without write access to trigger Claude Code Action workflows. This can introduce security risks.
If this is a new flow, please make sure you actually need `allowed_non_write_users`. If you are editing an existing workflow, double check that you are not adding new Claude permissions which might lead to a vulnerability.
See existing workflows in this repo for safe usage examples, or contact the AppSec team.'
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}

View File

@@ -1,5 +1,22 @@
# Changelog
## 2.1.52
- VS Code: Fixed extension crash on Windows ("command 'claude-vscode.editor.openLast' not found")
## 2.1.51
- Added `claude remote-control` subcommand for external builds, enabling local environment serving for all users.
- Updated plugin marketplace default git timeout from 30s to 120s and added `CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS` to configure.
- Added support for custom npm registries and specific version pinning when installing plugins from npm sources
- BashTool now skips login shell (`-l` flag) by default when a shell snapshot is available, improving command execution performance. Previously this required setting `CLAUDE_BASH_NO_LOGIN=true`.
- Fixed a security issue where `statusLine` and `fileSuggestion` hook commands could execute without workspace trust acceptance in interactive mode.
- Tool results larger than 50K characters are now persisted to disk (previously 100K). This reduces context window usage and improves conversation longevity.
- Fixed a bug where duplicate `control_response` messages (e.g. from WebSocket reconnects) could cause API 400 errors by pushing duplicate assistant messages into the conversation.
- Added `CLAUDE_CODE_ACCOUNT_UUID`, `CLAUDE_CODE_USER_EMAIL`, and `CLAUDE_CODE_ORGANIZATION_UUID` environment variables for SDK callers to provide account info synchronously, eliminating a race condition where early telemetry events lacked account metadata.
- Fixed slash command autocomplete crashing when a plugin's SKILL.md description is a YAML array or other non-string type
- The `/model` picker now shows human-readable labels (e.g., "Sonnet 4.5") instead of raw model IDs for pinned model versions, with an upgrade hint when a newer version is available.
## 2.1.50
- Added support for `startupTimeout` configuration for LSP servers

87
scripts/edit-issue-labels.sh Executable file
View File

@@ -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

43
scripts/gh.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
set -euo pipefail
# Wrapper around gh CLI that only allows specific subcommands and flags.
#
# Usage:
# ./scripts/gh.sh issue view 123
# ./scripts/gh.sh issue view 123 --comments
# ./scripts/gh.sh issue list --state open --limit 20
# ./scripts/gh.sh search issues "search query" --limit 10
# ./scripts/gh.sh label list --limit 100
ALLOWED_FLAGS=(--comments --state --limit --label)
SUB1="${1:-}"
SUB2="${2:-}"
CMD="$SUB1 $SUB2"
case "$CMD" in
"issue view"|"issue list"|"search issues"|"label list")
;;
*)
exit 1
;;
esac
shift 2
for arg in "$@"; do
if [[ "$arg" == -* ]]; then
flag="${arg%%=*}"
matched=false
for allowed in "${ALLOWED_FLAGS[@]}"; do
if [[ "$flag" == "$allowed" ]]; then
matched=true
break
fi
done
if [[ "$matched" == false ]]; then
exit 1
fi
fi
done
gh "$SUB1" "$SUB2" "$@"