Repository navigation
feat: implement issue #232 — Phase 1: Issue Triage gh-aw workflow #284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
961e1cc
feat: implement issue #232 — Phase 1: Issue Triage gh-aw workflow
donpetry-bot b4abacf
fix(bot): address bot feedback [skip ci-relay]
donpetry-bot a2ad3dd
fix(ci): auto-fix for SonarCloud Code Analysis [skip ci-relay]
donpetry-bot 568b293
chore: apply manual instructions [skip ci-relay]
donpetry-bot a563cc7
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry a95a13f
chore: apply manual instructions [skip ci-relay]
donpetry-bot 765c03b
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 14872f7
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 86792aa
chore: apply manual instructions [skip ci-relay]
donpetry-bot bbc4b28
fix(reviews): address review comments [skip ci-relay]
donpetry-bot 43c8ade
fix(reviews): address review comments [skip ci-relay]
donpetry-bot 73d9979
fix(reviews): address review comments [skip ci-relay]
donpetry-bot 76b0b2e
fix(bot): address bot feedback [skip ci-relay]
donpetry-bot 44dd640
fix(bot): address bot feedback [skip ci-relay]
donpetry-bot 84798b9
fix(ci): auto-fix for SonarCloud Code Analysis [skip ci-relay]
donpetry-bot a7aff0a
fix(ci): auto-fix for SonarCloud Code Analysis [skip ci-relay]
donpetry-bot b9da230
fix(ci): auto-fix for SonarCloud Code Analysis [skip ci-relay]
donpetry-bot e606888
chore: apply manual instructions [skip ci-relay]
donpetry-bot 94a474c
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry b6e9ac2
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 159c1ba
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry a87caba
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 5ba8f6c
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry b56a45f
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 4d29d08
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 3835418
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 4e7ba5a
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 78fee82
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry b31476b
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 231cf47
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry c813b80
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry e57f55c
chore: sync ci.yml with main to resolve merge conflict
don-petry 3ac105a
chore: sync test.yml with main to resolve merge conflict
don-petry a82c836
fix(aw): remove 'name' field from issue-triage.md frontmatter (not al…
don-petry 1802171
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 5da1d8f
fix(aw): correct issue-triage.md frontmatter for gh-aw schema (on:, s…
don-petry 2608183
Merge branch 'main' into dev-lead/issue-232-20260519-0317
don-petry 64c8594
fix(aw): use minimal valid gh-aw frontmatter for issue-triage.md
don-petry da22717
fix(aw): use correct add-labels schema in issue-triage.md
don-petry 306fe58
fix(aw): remove stale frontmatter from body of issue-triage.md
don-petry 5eac9c3
fix(aw): clean up issue-triage.md — remove duplicate frontmatter from…
don-petry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,3 +132,4 @@ | |
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| name: Issue Triage | ||
|
|
||
| on: | ||
| issues: | ||
| types: [opened, reopened] | ||
|
|
||
| # Two-job pattern: triage runs with read-only issue access and produces a | ||
| # staged JSON artifact; apply runs with write access and calls safe-output. | ||
| jobs: | ||
| triage: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
| permissions: | ||
| contents: read | ||
| issues: read | ||
|
don-petry marked this conversation as resolved.
|
||
| outputs: | ||
| result: ${{ steps.run.outputs.result }} | ||
| skip: ${{ steps.run.outputs.skip }} | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
|
coderabbitai[bot] marked this conversation as resolved.
don-petry marked this conversation as resolved.
|
||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Install claude CLI | ||
| uses: anthropics/claude-code-action/setup@24492741e0ccfdef4c1d19da8e11e0f373d07494 # main | ||
| with: | ||
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | ||
|
|
||
| - name: Install Python dependencies | ||
| run: pip install "pyyaml==6.0.3" --only-binary :all: --quiet | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| - name: Run issue-triage (staged) | ||
| id: run | ||
| env: | ||
| ISSUE_NUMBER: ${{ github.event.issue.number }} | ||
| ISSUE_TITLE: ${{ github.event.issue.title }} | ||
| ISSUE_BODY: ${{ github.event.issue.body }} | ||
| ISSUE_LABELS: ${{ join(github.event.issue.labels.*.name, ',') }} | ||
| ISSUE_URL: ${{ github.event.issue.html_url }} | ||
| ISSUE_ACTION: ${{ github.event.action }} | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
|
don-petry marked this conversation as resolved.
|
||
| run: | | ||
| set -euo pipefail | ||
| result=$(bash scripts/aw.sh run issue-triage --staged) | ||
| skip=$(AW_RESULT="$result" python3 - <<'PYEOF' | ||
| import json, os | ||
| d = json.loads(os.environ['AW_RESULT']) | ||
| print('true' if d.get('skip') else 'false') | ||
| PYEOF | ||
| ) | ||
| # Store encoded to survive multi-line JSON in GITHUB_OUTPUT | ||
| encoded=$(printf '%s\n' "$result" | base64 -w0) | ||
| echo "result=$encoded" >> "$GITHUB_OUTPUT" | ||
| echo "skip=$skip" >> "$GITHUB_OUTPUT" | ||
|
|
||
| apply: | ||
| needs: triage | ||
| if: needs.triage.outputs.skip != 'true' | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 3 | ||
| permissions: | ||
| contents: read | ||
| issues: write | ||
|
don-petry marked this conversation as resolved.
|
||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Install Python dependencies | ||
| run: pip install "pyyaml==6.0.3" --only-binary :all: --quiet | ||
|
|
||
| - name: Apply triage output (safe-output) | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| ISSUE_NUMBER: ${{ github.event.issue.number }} | ||
| TRIAGE_RESULT: ${{ needs.triage.outputs.result }} | ||
| run: | | ||
| result_file=$(mktemp) | ||
| printf '%s\n' "$TRIAGE_RESULT" | base64 -d > "$result_file" | ||
| bash scripts/aw.sh safe-output apply issue-triage "$result_file" | ||
| rm -f "$result_file" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| --- | ||
| on: | ||
| issues: | ||
| types: [opened] | ||
| engine: claude-sonnet-4-6 | ||
| permissions: | ||
| issues: read | ||
| safe-outputs: | ||
| add-labels: | ||
| allowed: | ||
| - bug | ||
| - enhancement | ||
| - documentation | ||
| - question | ||
| - needs-triage | ||
| - good-first-issue | ||
| - security | ||
| max: 3 | ||
| --- | ||
|
|
||
| # Issue Triage | ||
|
|
||
| You are triaging a new GitHub issue for the `${REPO}` repository. | ||
|
|
||
| ## Context | ||
|
|
||
| - **Repository:** `${REPO}` | ||
| - **Issue:** [#${ISSUE_NUMBER}](${ISSUE_URL}): ${ISSUE_TITLE} | ||
| - **Labels already applied:** ${ISSUE_LABELS} | ||
|
don-petry marked this conversation as resolved.
|
||
|
|
||
| **Issue body:** | ||
|
|
||
| ${ISSUE_BODY} | ||
|
|
||
| ## Task | ||
|
|
||
| If the issue already has **2 or more labels**, output `{"skip": true}` and stop — do not classify, do not comment. | ||
|
don-petry marked this conversation as resolved.
|
||
|
|
||
| Otherwise: | ||
|
|
||
| 1. **Classify** the issue into the best-fit category: | ||
| - `bug` — something is not working as expected | ||
| - `enhancement` — request for new or extended functionality | ||
| - `documentation` — unclear, missing, or incorrect docs | ||
| - `question` — user asking how to do something | ||
| - `security` — potential security vulnerability | ||
| - `good-first-issue` — simple enough for a first-time contributor | ||
|
|
||
| 2. **Select ≤ 3 labels** from the allowed set: | ||
| `bug`, `enhancement`, `documentation`, `question`, `needs-triage`, | ||
| `good-first-issue`, `security`. | ||
| - Add `needs-triage` for bugs and ambiguous reports that need human review. | ||
| - Add `good-first-issue` only when the scope is clearly small and | ||
| self-contained. | ||
|
|
||
| 3. **Write one welcoming comment** that: | ||
| - Opens warmly and thanks the contributor. | ||
| - Asks the **single most important** clarifying question for this issue type: | ||
| - Bug → steps to reproduce + expected vs actual behaviour | ||
| - Feature → use case / motivation | ||
| - Question → what docs they checked and where they got stuck | ||
| - Documentation → which page or section is unclear and what they expected | ||
| - Security → (do not ask for details publicly; ask them to use the | ||
| private security advisory channel) | ||
| - Does **not** ask multiple unrelated questions. | ||
| - Is concise (≤ 5 sentences). | ||
|
|
||
| ## Output format | ||
|
|
||
| Output **exactly one** JSON object — no markdown fences, no preamble: | ||
|
|
||
| For a normal triage: | ||
| {"labels": ["label1", "label2"], "comment": "Your welcoming comment here."} | ||
|
|
||
| For a skip (issue already has 2+ labels): | ||
| {"skip": true} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Issue Triage — Agentic Workflow | ||
|
|
||
| Part of the GitHub Agentic Workflows rollout (internal discussion: [petry-projects/.github-private#228](https://github.com/petry-projects/.github-private/discussions/228) — requires repo access). | ||
|
|
||
| ## What it does | ||
|
|
||
| When a new issue is opened or reopened, this workflow: | ||
|
|
||
| 1. Checks the existing label count. If the issue already has **2 or more labels** it exits silently (no-op). | ||
| 2. Calls Claude (`claude-sonnet-4-6`) with the issue title and body to classify the issue. | ||
| 3. Selects up to 3 labels from the allowed set and writes a single welcoming comment that asks the most relevant clarifying question. | ||
|
|
||
| All of this happens within 60 seconds of the issue being opened. | ||
|
|
||
| ## Allowed labels | ||
|
|
||
| `bug`, `enhancement`, `documentation`, `question`, `needs-triage`, `good-first-issue`, `security` | ||
|
|
||
| ## Files | ||
|
|
||
| | File | Purpose | | ||
| |------|---------| | ||
| | `.github/workflows/issue-triage.md` | Workflow definition (frontmatter + Claude prompt template) | | ||
| | `.github/workflows/issue-triage-runner.yml` | GitHub Actions runner (two-job: triage → apply) | | ||
| | `scripts/aw.sh` | `gh aw` CLI — compile, run, safe-output | | ||
| | `tests/aw/issue-triage/scenarios.md` | Scenario spec used to validate behaviour | | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| issues: opened/reopened | ||
| │ | ||
| ▼ | ||
| triage job (permissions: issues: read) | ||
| │ bash scripts/aw.sh run issue-triage --staged | ||
| │ → Claude classifies, returns JSON | ||
| ▼ | ||
| apply job (permissions: issues: write) | ||
| │ bash scripts/aw.sh safe-output apply issue-triage result.json | ||
| │ → validates labels, posts comment, adds labels | ||
| ▼ | ||
| issue updated | ||
| ``` | ||
|
|
||
| The two-job split is deliberate: Claude runs with the minimum permission it | ||
| needs (read), and writes are applied by a separate job after the output has | ||
| been validated by `safe-output`. | ||
|
|
||
| ## Validation | ||
|
|
||
| `gh aw compile` validates every `.md` workflow definition file. It checks: | ||
|
|
||
| - Required frontmatter fields: `name`, `trigger`, `engine`, `permissions` | ||
| - Engine is a known Claude model identifier | ||
| - `output` is `staged` or `live` (if present) | ||
| - Trigger is a non-empty event mapping | ||
| - Workflow body (instructions) is not empty | ||
|
|
||
| Run locally: | ||
|
|
||
| ```bash | ||
| bash scripts/aw.sh compile .github/workflows/issue-triage.md | ||
| ``` | ||
|
|
||
| ## Staged vs live mode | ||
|
|
||
| The `output` frontmatter field controls how results are applied: | ||
|
|
||
| | Value | Behaviour | | ||
| |-------|-----------| | ||
| | `staged` | `aw run` emits JSON to stdout; a separate `safe-output apply` step writes to GitHub | | ||
| | `live` (default when omitted) | `aw run` applies labels and posts the comment inline | | ||
|
|
||
| The runner workflow always uses the two-job pattern regardless of this setting, | ||
| so `safe-output` always validates before writing. | ||
|
|
||
| ## Skip condition | ||
|
|
||
| If the issue already has **2 or more labels** when the workflow fires, `aw run` | ||
| returns `{"skip": true}` immediately and the apply job is skipped. No API | ||
| writes occur. | ||
|
|
||
| ## Smoke-test procedure | ||
|
|
||
| To validate against the scenario spec before going live: | ||
|
|
||
| ```bash | ||
| # Create a test issue in a non-critical repo and capture the number | ||
| ISSUE_NUMBER=<n> \ | ||
| ISSUE_TITLE="Login button is broken" \ | ||
| ISSUE_BODY="When I click nothing happens." \ | ||
| ISSUE_LABELS="" \ | ||
| ISSUE_URL="https://github.com/petry-projects/.github-private/issues/<n>" \ | ||
| GITHUB_REPOSITORY="petry-projects/.github-private" \ | ||
| bash scripts/aw.sh run issue-triage --staged | ||
| ``` | ||
|
|
||
| Compare the JSON output against the expected labels and comment style in | ||
| `tests/aw/issue-triage/scenarios.md`. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.