claude-code-ultimate-guide/examples/github-actions/claude-issue-triage.yml
Florian BRUNIAUX 87994bb797 feat(guide): add thinking keywords, GitHub Actions examples, and improvement recommendations
Documentation enhancements:
- Add inline thinking keywords section (think, think hard, ultrathink) with usage examples
- Create examples/github-actions/ directory with 3 ready-to-use workflows:
  * Auto PR review with inline comments
  * Security review on every PR
  * Issue triage with label suggestions
- Add comprehensive IMPROVEMENT_RECOMMENDATIONS.md with prioritized action items

Improvements based on zebbern/claude-code-guide analysis:
- Enhanced troubleshooting guidance
- Format enhancements (badges, collapsible tables, C-style comments)
- Security/performance/workflow pitfalls sections
- DeepSeek integration documentation
- One-shot health check scripts

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-10 15:26:18 +01:00

101 lines
4.1 KiB
YAML

name: Claude Issue Triage
on:
issues:
types: [opened, edited, reopened]
permissions:
contents: read
issues: write
jobs:
triage:
runs-on: ubuntu-latest
env:
CLAUDE_MODEL: claude-3-5-sonnet-20240620
steps:
- name: Collect context & similar issues
id: gather
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TITLE="${{ github.event.issue.title }}"
BODY="${{ github.event.issue.body }}"
# naive similar search by title words
Q=$(echo "$TITLE" | tr -dc '[:alnum:] ' | awk '{print $1" "$2" "$3" "$4}')
gh api -X GET search/issues -f q="repo:${{ github.repository }} is:issue $Q" -f per_page=5 > similars.json
echo "$TITLE" > title.txt
echo "$BODY" > body.txt
- name: Ask Claude for triage JSON
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
cat > payload.json << 'JSON'
{
"model": "${{ env.CLAUDE_MODEL }}",
"max_tokens": 1500,
"system": "You are a pragmatic triage engineer. Be specific, cautious with duplicates.",
"messages": [{
"role": "user",
"content": [{
"type":"text",
"text":"Given the issue and similar candidates, produce STRICT JSON with keys: labels (array of strings), severity (one of: low, medium, high, critical), duplicate_url (string or empty), comment_markdown (string brief). Do not include any extra keys."
},
{"type":"text","text":"Issue title:\n"},
{"type":"text","text": "PLACEHOLDER_TITLE"},
{"type":"text","text":"\n\nIssue body:\n"},
{"type":"text","text": "PLACEHOLDER_BODY"},
{"type":"text","text":"\n\nSimilar issues (JSON):\n"},
{"type":"text","text": "PLACEHOLDER_SIMILARS"}]
}]
}
JSON
# Inject files safely
jq --arg title "$(cat title.txt)" '.messages[0].content[2].text = $title' payload.json \
| jq --arg body "$(cat body.txt)" '.messages[0].content[4].text = $body' \
| jq --arg sims "$(cat similars.json)" '.messages[0].content[6].text = $sims' > payload.final.json
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d @payload.final.json > out.json
jq -r '.content[0].text' out.json > triage.json || echo '{}' > triage.json
# Validate JSON to avoid posting garbage
jq -e . triage.json >/dev/null 2>&1 || echo '{"labels":[],"severity":"low","duplicate_url":"","comment_markdown":"(triage failed to parse)"}' > triage.json
- name: Apply labels (optional)
if: ${{ false }} # flip to `true` to auto-apply labels
uses: actions/github-script@v7
with:
script: |
const triage = JSON.parse(require('fs').readFileSync('triage.json','utf8'))
if (triage.labels?.length) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: triage.labels
})
}
- name: Post triage comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs')
const triage = JSON.parse(fs.readFileSync('triage.json','utf8'))
const md = `### 🤖 Triage
- **Suggested labels:** ${triage.labels?.join(', ') || '—'}
- **Severity:** ${triage.severity || '—'}
${triage.duplicate_url ? `- **Possible duplicate:** ${triage.duplicate_url}\n` : ''}
---
${triage.comment_markdown || ''}`
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: md
})