From 0e7cf82ad521a2573dce11274fa2e2b3cd4a89df Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Thu, 11 Dec 2025 10:02:03 -0800 Subject: [PATCH 1/6] feat: add repository_dispatch trigger for Linear issue triage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add repository_dispatch trigger with type `linear-triage` - Fix format() function to properly inject client_payload fields - Remove unused linear_team_prefix input - Update prompt to focus on Linear issue triage workflow - Update README with repository dispatch documentation - Update CLAUDE.md with accurate workflow description 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/issue-triage.yml | 74 ++++++++++++--------------- CLAUDE.md | 6 +-- README.md | 81 ++++++++++++++++++++---------- 3 files changed, 88 insertions(+), 73 deletions(-) diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index 647d526..2439c7e 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -3,12 +3,6 @@ name: Issue Triage on: workflow_call: inputs: - linear_team_prefix: - description: - 'Linear team prefix for ticket references (e.g., "PROJ" for PROJ-123)' - type: string - required: false - default: '' allowed_tools: description: 'Comma-separated list of allowed tools for Claude' type: string @@ -30,6 +24,9 @@ on: description: 'Linear API token' required: true + repository_dispatch: + types: [linear-triage] + permissions: contents: read pull-requests: read @@ -43,14 +40,19 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: + repository: + ${{ github.event.client_payload.target_repo || github.repository }} fetch-depth: 0 - name: Triage Issue uses: anthropics/claude-code-action@v1 env: - LINEAR_API_TOKEN: ${{ secrets.linear_api_token }} + LINEAR_API_TOKEN: + ${{ secrets.linear_api_token || secrets.LINEAR_API_TOKEN }} with: - claude_code_oauth_token: ${{ secrets.claude_code_oauth_token }} + claude_code_oauth_token: + ${{ secrets.claude_code_oauth_token || + secrets.CLAUDE_CODE_OAUTH_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }} track_progress: true settings: | @@ -62,53 +64,39 @@ jobs: } } } - claude_args: --allowedTools "${{ inputs.allowed_tools }}" + claude_args: + --allowedTools "${{ inputs.allowed_tools || + github.event.client_payload.allowed_tools || + 'Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*' + }}" prompt: | - ${{ inputs.prompt || format('**Issue Triage Task** + ${{ inputs.prompt || github.event.client_payload.prompt || format('**Linear Issue Triage Task** + + A Linear issue needs triage: {0} - A new GitHub issue has been created. Linear is the source of truth for all tickets. + Issue ID: {1} + Title: {2} ## Your Tasks - ### 1. Understand the Request - - Read the issue title and description - - Identify type: bug, feature, enhancement, or question - - Determine scope and complexity + ### 1. Fetch Issue Details + - Use Linear MCP to fetch the full issue details for {1} + - Review the issue description, labels, and current status ### 2. Research the Codebase - Search for related code, components, or existing implementations - Identify files that would likely need changes - Check for similar functionality - ### 3. Ask Clarifying Questions (if needed) - - If vague or missing key info, ask specific questions - - For bugs: request reproduction steps, expected vs actual behavior - - For features: clarify acceptance criteria - - ### 4. Apply Labels - Use `gh label list` to see available labels, then apply appropriate ones: - ```bash - gh issue edit $ISSUE_NUMBER --add-label "bug" --add-label "priority:high" - ``` - - ### 5. Linear Integration - Check if this issue is already linked to a Linear ticket (look for {0}-XXX in the issue body or comments). - - **If NO Linear ticket exists:** - - Use the Linear MCP tools to create a new ticket - - Link it back to this GitHub issue - - Add a comment with the Linear ticket ID (e.g., "Created Linear ticket: {0}-123") - - **If a Linear ticket already exists:** - - Fetch the ticket details using Linear MCP - - Update the GitHub issue with any additional context from Linear - - ### 6. Provide Analysis Summary - Comment with: - - Your understanding of the request + ### 3. Update Linear Ticket + Update the Linear ticket with your analysis: - Files/components likely involved - Complexity estimate (small/medium/large) - Any dependencies or blockers - - Linear ticket reference + - Implementation suggestions or approach + + ### 4. Update Ticket Status + - Move the ticket from Triage to the appropriate next status + - Add any relevant labels if needed - Be concise and actionable.', inputs.linear_team_prefix) }} + Be concise and actionable.', github.event.client_payload.url, github.event.client_payload.issue_id, github.event.client_payload.title) }} diff --git a/CLAUDE.md b/CLAUDE.md index 39b9dd1..51aa4a5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,9 +49,9 @@ Each workflow defines: for triage) - `permissions` - GitHub token scopes needed -The `issue-triage.yml` workflow has conditional steps based on `enable_linear` -and `prompt` inputs to handle four combinations: with/without Linear, -with/without custom prompt. +The `issue-triage.yml` workflow is triggered via `repository_dispatch` (type: +`linear-triage`) for Linear webhook integration. It uses the `format()` function +to inject `client_payload` fields (issue_id, url, title) into the prompt. The `code-review.yml` workflow includes additional `actions/github-script` steps for check run management and emoji reactions. diff --git a/README.md b/README.md index 011db3e..2f02f8b 100644 --- a/README.md +++ b/README.md @@ -60,25 +60,42 @@ jobs: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} ``` -### With Issue Triage +### With Linear Issue Triage (Repository Dispatch) + +Trigger issue triage from Linear webhooks via repository dispatch: ```yaml -name: Claude Code +name: Linear Issue Triage on: - issues: - types: [opened] + repository_dispatch: + types: [linear-triage] jobs: triage: uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@main - with: - linear_team_prefix: 'PROJ' secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} linear_api_token: ${{ secrets.LINEAR_API_KEY }} ``` +To trigger, send a POST request to GitHub's repository dispatch API: + +```bash +curl -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/OWNER/REPO/dispatches \ + -d '{ + "event_type": "linear-triage", + "client_payload": { + "issue_id": "PROJ-123", + "url": "https://linear.app/team/issue/PROJ-123", + "title": "Issue title" + } + }' +``` + ### With Manual Code Review Triggered by `/review` comment on a PR: @@ -160,15 +177,29 @@ permissions: ### issue-triage.yml -Automated issue triage with Linear integration. +Automated Linear issue triage via repository dispatch. + +#### Triggers + +- `repository_dispatch` with type `linear-triage` +- `workflow_call` for reusable workflow usage #### Inputs -| Input | Type | Default | Description | -| -------------------- | ------ | -------------------------------------------------------------------- | ------------------------------------------------ | -| `linear_team_prefix` | string | `''` | Linear team prefix (e.g., `PROJ` for `PROJ-123`) | -| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*` | Comma-separated list of allowed tools | -| `prompt` | string | `''` | Custom prompt (overrides default) | +| Input | Type | Default | Description | +| --------------- | ------ | -------------------------------------------------------------------- | --------------------------------- | +| `allowed_tools` | string | `Read,Grep,Glob,LS,Bash(gh issue:*),Bash(gh label:*),mcp__linear__*` | Comma-separated list of tools | +| `prompt` | string | `''` | Custom prompt (overrides default) | + +#### Repository Dispatch Payload + +| Field | Required | Description | +| ------------- | -------- | --------------------------------------------- | +| `issue_id` | Yes | Linear issue ID (e.g., `PROJ-123`) | +| `url` | Yes | Linear issue URL | +| `title` | Yes | Linear issue title | +| `target_repo` | No | Target repo to checkout (defaults to current) | +| `prompt` | No | Custom prompt override | #### Secrets @@ -191,13 +222,11 @@ permissions: When no custom `prompt` is provided, the workflow: -1. Analyzes the issue title and description -2. Identifies the issue type (bug, feature, enhancement, question) -3. Researches related code in the repository -4. Asks clarifying questions if needed -5. Applies appropriate labels -6. Creates/links Linear tickets -7. Posts an analysis summary +1. Fetches full issue details from Linear via MCP +2. Researches related code in the repository +3. Updates the Linear ticket with analysis (files involved, complexity, + implementation suggestions) +4. Moves the ticket from Triage to the appropriate status --- @@ -264,27 +293,25 @@ on: types: [created] pull_request_review_comment: types: [created] - issues: - types: [opened, labeled] pull_request_review: types: [submitted] + repository_dispatch: + types: [linear-triage] jobs: # General Claude agent for comments claude: if: | - !contains(github.event.comment.body, '/review') && - github.event_name != 'issues' + github.event_name != 'repository_dispatch' && + !contains(github.event.comment.body, '/review') uses: zaks-io/claude-code-action/.github/workflows/claude.yml@main secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - # Issue triage on new issues + # Issue triage via repository dispatch (triggered by Linear webhook) triage: - if: github.event_name == 'issues' && github.event.action == 'opened' + if: github.event_name == 'repository_dispatch' uses: zaks-io/claude-code-action/.github/workflows/issue-triage.yml@main - with: - linear_team_prefix: 'PROJ' secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} linear_api_token: ${{ secrets.LINEAR_API_KEY }} From 6b05c97071151051edbd60ec7e601e5f4a4d3a1d Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Thu, 11 Dec 2025 10:07:39 -0800 Subject: [PATCH 2/6] feat: add automatic code review to CI pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add code-review job that runs after pre-commit checks pass on non-draft PRs. Uses the code-review.yml reusable workflow with trigger_type: auto. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe2e9bf..bb3c7ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: push: branches: [main] pull_request: + types: [opened, synchronize, ready_for_review] jobs: pre-commit: @@ -20,3 +21,15 @@ jobs: - name: Run pre-commit uses: pre-commit/action@v3.0.1 + + code-review: + name: Code Review + needs: [pre-commit] + if: + github.event_name == 'pull_request' && github.event.pull_request.draft == + false + uses: ./.github/workflows/code-review.yml + with: + trigger_type: auto + secrets: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} From 3f39963b411d249990c99ddc08874ffae03e7de9 Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Thu, 11 Dec 2025 10:11:18 -0800 Subject: [PATCH 3/6] fix: add permissions for code-review workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb3c7ea..5a760ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,13 @@ on: pull_request: types: [opened, synchronize, ready_for_review] +permissions: + contents: read + pull-requests: write + checks: write + id-token: write + actions: read + jobs: pre-commit: name: Pre-commit Checks From fb9a9805a8b84959845f8185cbc00fb2e7f6ca7e Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Thu, 11 Dec 2025 10:15:15 -0800 Subject: [PATCH 4/6] fix: improve format() readability in issue-triage prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move format() arguments to separate lines for better YAML parsing reliability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/issue-triage.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index 2439c7e..f33a6e4 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -73,7 +73,6 @@ jobs: ${{ inputs.prompt || github.event.client_payload.prompt || format('**Linear Issue Triage Task** A Linear issue needs triage: {0} - Issue ID: {1} Title: {2} @@ -99,4 +98,7 @@ jobs: - Move the ticket from Triage to the appropriate next status - Add any relevant labels if needed - Be concise and actionable.', github.event.client_payload.url, github.event.client_payload.issue_id, github.event.client_payload.title) }} + Be concise and actionable.', + github.event.client_payload.url, + github.event.client_payload.issue_id, + github.event.client_payload.title) }} From 748cb4bd8452f716f4387ce1228481d1eae63fe0 Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Thu, 11 Dec 2025 10:17:31 -0800 Subject: [PATCH 5/6] fix: remove target_repo from issue-triage workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The workflow runs in each repo that includes it, so it should always checkout the current repository. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/issue-triage.yml | 2 -- README.md | 13 ++++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index f33a6e4..a8bf281 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -40,8 +40,6 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - repository: - ${{ github.event.client_payload.target_repo || github.repository }} fetch-depth: 0 - name: Triage Issue diff --git a/README.md b/README.md index 2f02f8b..a95c2ad 100644 --- a/README.md +++ b/README.md @@ -193,13 +193,12 @@ Automated Linear issue triage via repository dispatch. #### Repository Dispatch Payload -| Field | Required | Description | -| ------------- | -------- | --------------------------------------------- | -| `issue_id` | Yes | Linear issue ID (e.g., `PROJ-123`) | -| `url` | Yes | Linear issue URL | -| `title` | Yes | Linear issue title | -| `target_repo` | No | Target repo to checkout (defaults to current) | -| `prompt` | No | Custom prompt override | +| Field | Required | Description | +| ---------- | -------- | ---------------------------------- | +| `issue_id` | Yes | Linear issue ID (e.g., `PROJ-123`) | +| `url` | Yes | Linear issue URL | +| `title` | Yes | Linear issue title | +| `prompt` | No | Custom prompt override | #### Secrets From 0a5a023e8c3e39ed0f770155d18e7d7b1863611a Mon Sep 17 00:00:00 2001 From: Isaac Suttell Date: Thu, 11 Dec 2025 10:20:28 -0800 Subject: [PATCH 6/6] fix: only run code review on PR open, ready_for_review, or /review comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove synchronize trigger (don't review on every push) - Add issue_comment trigger for /review command - Split into code-review-auto and code-review-manual jobs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/ci.yml | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a760ba..d854c71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,9 @@ on: push: branches: [main] pull_request: - types: [opened, synchronize, ready_for_review] + types: [opened, ready_for_review] + issue_comment: + types: [created] permissions: contents: read @@ -29,14 +31,26 @@ jobs: - name: Run pre-commit uses: pre-commit/action@v3.0.1 - code-review: - name: Code Review + code-review-auto: + name: Code Review (Auto) needs: [pre-commit] - if: - github.event_name == 'pull_request' && github.event.pull_request.draft == - false + if: | + github.event_name == 'pull_request' && + github.event.pull_request.draft == false uses: ./.github/workflows/code-review.yml with: trigger_type: auto secrets: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + code-review-manual: + name: Code Review (Manual) + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, '/review') + uses: ./.github/workflows/code-review.yml + with: + trigger_type: comment + secrets: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}