-
-
Notifications
You must be signed in to change notification settings - Fork 100
243 lines (216 loc) · 11.5 KB
/
claude.yml
File metadata and controls
243 lines (216 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]
jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- name: Assign issue to Claude
if: github.event_name == 'issues' || github.event_name == 'issue_comment'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get issue number
if [[ "${{ github.event_name }}" == "issues" ]]; then
ISSUE_NUMBER=${{ github.event.issue.number }}
elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then
ISSUE_NUMBER=${{ github.event.issue.number }}
fi
# Check if issue is already assigned to anyone
CURRENT_ASSIGNEE=$(gh issue view $ISSUE_NUMBER --json assignees --jq '.assignees[0].login // empty')
if [[ -z "$CURRENT_ASSIGNEE" ]]; then
echo "Assigning issue #$ISSUE_NUMBER to indicate Claude is working on it"
# Assign to the repository owner or a service account
gh issue edit $ISSUE_NUMBER --add-assignee tphakala || echo "Could not assign issue"
# Add a label to indicate Claude is working on this
gh label create "claude-working" --description "Claude is currently working on this issue" --color "1d76db" 2>/dev/null || true
gh issue edit $ISSUE_NUMBER --add-label "claude-working" || echo "Could not add label"
# Auto-assign package labels based on issue content
ISSUE_BODY=$(gh issue view $ISSUE_NUMBER --json body --jq '.body')
ISSUE_TITLE=$(gh issue view $ISSUE_NUMBER --json title --jq '.title')
COMBINED_TEXT="$ISSUE_TITLE $ISSUE_BODY"
# Detect packages mentioned in the issue and add appropriate labels
if echo "$COMBINED_TEXT" | grep -i "analysis\|processor" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:analysis" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "myaudio\|audio.*processing" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:myaudio" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "api\|endpoint\|http.*handler" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:api" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "birdnet\|neural.*network" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:birdnet" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "datastore\|database\|sql" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:datastore" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "diskmanager\|disk.*space" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:diskmanager" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "telemetry\|metrics" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:telemetry" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "monitor\|health.*check" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:monitor" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "mqtt\|messaging" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:mqtt" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "notification\|alert" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:notification" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "birdweather" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:birdweather" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "security\|auth\|login" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:security" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "config\|configuration" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:conf" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "error.*handling\|internal/errors" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:errors" 2>/dev/null || true
fi
if echo "$COMBINED_TEXT" | grep -i "test.*fail\|unit.*test" >/dev/null; then
gh issue edit $ISSUE_NUMBER --add-label "pkg:testing" 2>/dev/null || true
fi
# Add a comment to indicate Claude has been assigned
{
echo "🤖 **Claude Assigned**"
echo ""
echo "This issue has been automatically assigned to Claude for resolution. Claude will:"
echo "- Analyze the problem"
echo "- Implement fixes following project guidelines"
echo "- Run tests to verify the solution"
echo "- Create a pull request with the changes"
echo ""
echo "Status: **Working** 🔄"
} > /tmp/assignment-comment.md
gh issue comment $ISSUE_NUMBER --body-file /tmp/assignment-comment.md || echo "Could not add comment"
else
echo "Issue #$ISSUE_NUMBER is already assigned to $CURRENT_ASSIGNEE"
fi
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read
# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
# model: "claude-opus-4-20250514"
# Optional: Customize the trigger phrase (default: @claude)
# trigger_phrase: "/claude"
# Optional: Trigger when specific user is assigned to an issue
# assignee_trigger: "claude-bot"
# Allow Claude to run Go testing and development commands
allowed_tools: |
Bash(go test *)
Bash(go build *)
Bash(go mod *)
Bash(golangci-lint run *)
Bash(task *)
Bash(git *)
Read(*_test.go)
Edit(*_test.go)
MultiEdit(*_test.go)
Write(*_test.go)
Grep(*.go)
Glob(**/*_test.go)
Glob(**/*.go)
# Add Go and BirdNET-Go specific instructions
custom_instructions: |
You are working on BirdNET-Go, a Go implementation of BirdNET for real-time bird sound identification.
## Critical Rules
- **ALWAYS use `internal/errors` package** (never standard `errors`)
- **Run `golangci-lint run -v` before EVERY commit**
- **Follow all guidelines in CLAUDE.md exactly**
## Testing Guidelines
- Use `t.TempDir()` for temporary directories (automatic cleanup)
- Use `t.Parallel()` only when tests are truly independent
- Avoid `time.Sleep()` - use channels/synchronization instead
- Structure tests: setup → execution → assertion
- Use table-driven tests with `t.Run()` for comprehensive coverage
## Error Handling
- Always use `internal/errors` package
- Wrap errors with context: `fmt.Errorf("operation failed: %w", err)`
- Specify `.Component()` and `.Category()` for telemetry
## Code Quality
- Use modern Go patterns (any instead of interface{})
- Use standard library first before external dependencies
- Follow security best practices
- Validate all user input
- Use `for i := range n` for Go 1.22+ patterns
## When fixing tests
- Focus ONLY on failing tests
- Read the test failure details carefully
- Understand the root cause before fixing
- Verify fixes by running tests
- Ensure fixes follow project patterns
- name: Update issue status after Claude completion
if: (github.event_name == 'issues' || github.event_name == 'issue_comment') && always()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get issue number
if [[ "${{ github.event_name }}" == "issues" ]]; then
ISSUE_NUMBER=${{ github.event.issue.number }}
elif [[ "${{ github.event_name }}" == "issue_comment" ]]; then
ISSUE_NUMBER=${{ github.event.issue.number }}
fi
# Check if Claude step was successful
if [[ "${{ steps.claude.outcome }}" == "success" ]]; then
echo "Claude completed successfully, updating issue status"
# Remove working label and add completed label
gh label create "claude-completed" --description "Claude has completed work on this issue" --color "28a745" 2>/dev/null || true
gh issue edit $ISSUE_NUMBER --remove-label "claude-working" 2>/dev/null || true
gh issue edit $ISSUE_NUMBER --add-label "claude-completed" || echo "Could not update labels"
# Add completion comment
{
echo "✅ **Claude Work Completed**"
echo ""
echo "Claude has finished analyzing and working on this issue. Please review any pull requests or changes that were made."
echo ""
echo "Status: **Completed** ✅"
} > /tmp/completion-comment.md
gh issue comment $ISSUE_NUMBER --body-file /tmp/completion-comment.md || echo "Could not add completion comment"
else
echo "Claude encountered an issue, updating status"
# Add error label
gh label create "claude-error" --description "Claude encountered an error while working on this issue" --color "dc3545" 2>/dev/null || true
gh issue edit $ISSUE_NUMBER --remove-label "claude-working" 2>/dev/null || true
gh issue edit $ISSUE_NUMBER --add-label "claude-error" || echo "Could not update labels"
# Add error comment
{
echo "⚠️ **Claude Encountered an Issue**"
echo ""
echo "Claude was unable to complete work on this issue automatically. Please check the workflow logs for details and consider manual intervention."
echo ""
echo "Status: **Needs Review** ⚠️"
} > /tmp/error-comment.md
gh issue comment $ISSUE_NUMBER --body-file /tmp/error-comment.md || echo "Could not add error comment"
fi