Skip to content

Instantly share code, notes, and snippets.

@kevinold
Created March 4, 2026 22:32
Show Gist options
  • Select an option

  • Save kevinold/51304abc6c055e761a27a80877b522b4 to your computer and use it in GitHub Desktop.

Select an option

Save kevinold/51304abc6c055e761a27a80877b522b4 to your computer and use it in GitHub Desktop.
Claude Code + Compound Engineering GitHub Actions — Label-driven CI agent for automated issue triage, planning, fixing, and resolution

Claude Code GitHub Actions — Label-Driven CI Agent

A set of GitHub Actions workflows that use claude-code-action enhanced with the Compound Engineering plugin to automate issue triage, planning, fixing, and end-to-end resolution — all driven by GitHub issue labels.

Why Compound Engineering?

These workflows go beyond basic Claude Code Action by integrating the Compound Engineering plugin — a set of slash commands that give Claude structured, battle-tested workflows for planning and implementation:

Command What it does Used in
/ce:plan Creates structured implementation plans with architecture analysis, risk assessment, and step-by-step breakdown plan, solve jobs
/ce:work Implements changes systematically following a plan, with built-in quality checks fix (medium/large), solve jobs
/ce:review Performs thorough code reviews with multiple analysis passes @claude mentions on PRs
/ce:brainstorm Explores approaches collaboratively before committing to an implementation @claude mentions

Without the plugin, Claude handles tasks with generic prompting. With Compound Engineering, each phase uses a purpose-built workflow that produces more thorough, consistent results — especially for medium and large scope work.

The plugin is configured in each workflow via:

plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"

Overview

These workflows turn GitHub issues into an autonomous development pipeline. Apply a label to an issue, and Claude handles the rest — from understanding the problem to opening a PR with the fix.

Issue Created → label "triage" → Claude classifies & scopes
             → label "plan"   → Claude writes implementation plan (/ce:plan) + draft PR
             → label "fix"    → Claude implements a targeted fix (/ce:work) + PR
             → label "solve"  → Claude does all of the above end-to-end

You can also @claude in any issue or PR comment to interact directly (with full access to /ce: commands).

Files

.github/
├── actions/
│   └── setup-node/
│       └── action.yml          # Composite action: Node.js setup + npm cache
├── workflows/
│   ├── ci-agent.yml            # Label-triggered jobs (triage, plan, fix, solve)
│   ├── claude.yml              # @claude mention handler for issues & PRs
│   └── scheduled-triage.yml    # Cron job to auto-triage new issues

Setup

1. Add your API key

Add ANTHROPIC_API_KEY as a repository secret:

Settings → Secrets and variables → Actions → New repository secret

2. Copy the files

Copy the .github/ directory into your repository root.

3. Add a .nvmrc file

The setup-node action reads your Node.js version from .nvmrc:

22

4. Create the required labels

Create these labels in your repository (Issues → Labels → New label):

Trigger labels (apply these to activate workflows)

Label Color Description
triage #d4c5f9 Triggers AI triage — classifies and scopes the issue
plan #bfdadc Triggers AI planning — creates implementation plan + draft PR
fix #f9d0c4 Triggers AI fix — implements a targeted fix + PR
solve #0e8a16 Triggers full AI resolution — triage → plan → implement → PR

Classification labels (applied by AI during triage)

Label Color Description
bug #d73a4a Something isn't working
feature #a2eeef New feature or request
chore #fef2c0 Maintenance, dependencies, config
improvement #7057ff Enhancement to existing functionality

Scope labels (applied by AI during triage)

Label Color Description
scope:mini #e6e6e6 Trivial one-liner (typo, config value)
scope:small #c2e0c6 Under 1 hour, limited files
scope:medium #fbca04 1-4 hours, multiple files
scope:large #b60205 4+ hours, significant feature or refactor

Status labels (applied by AI during workflow)

Label Color Description
planned #0075ca Implementation plan exists
in-progress #006b75 Fix or solution in progress
autofix-candidate #2ea44f Good candidate for automated fix
needs-review #e4e669 PR needs human review (medium/low confidence)

5. Add a CLAUDE.md (recommended)

Create a CLAUDE.md in your repo root with project-specific context. This is read by Claude before every action. Include:

  • Project architecture overview
  • Key directories and files
  • Build/test/lint commands
  • Branch naming conventions
  • Any project-specific rules

How It Works

triage label

Claude reads the issue, reviews relevant code, and:

  • Classifies it (bug, feature, chore, improvement)
  • Estimates scope (mini, small, medium, large)
  • Flags it as autofix-candidate if appropriate
  • Comments with a summary
  • Removes the triage label

Model: Sonnet (fast, cost-effective) · Max turns: 8

plan label

Claude uses /ce:plan to create a structured implementation plan and:

  • Saves it to docs/plans/issue-{N}.md
  • Opens a draft PR with the plan
  • Adds the planned label
  • Comments with a summary + link

The Compound Engineering /ce:plan command produces plans with architecture analysis, affected areas, risk assessment, and step-by-step implementation details — far more thorough than unstructured planning.

Model: Opus (thorough planning) · Max turns: 15

fix label

Claude implements a fix, adapting its approach to scope:

Scope Model Max Turns Approach
mini Sonnet 15 Direct change, lint only
small Sonnet 15 Direct implementation + tests
medium Opus 20 /ce:work — systematic implementation
large Opus 30 /ce:work — systematic implementation

For medium and large scope issues, the Compound Engineering /ce:work command provides a structured implementation workflow with built-in quality gates.

After fixing:

  • Opens a PR (draft if confidence is medium/low)
  • Runs lint and tests
  • Comments with results + confidence assessment

solve label

Claude handles the entire lifecycle using Compound Engineering commands:

  1. Triage — classify and scope
  2. Plan/ce:plan to create implementation plan (skipped for mini scope)
  3. Implement/ce:work to write the code (medium/large) or direct implementation (mini/small)
  4. Deliver — branch, commit, PR
  5. Assess — confidence level, draft PR if uncertain

Model: Opus · Max turns: 35

@claude mentions

Mention @claude in any issue comment, PR review comment, or PR review to interact directly. Claude has full access to Compound Engineering commands:

  • /ce:review — thorough multi-pass code review
  • /ce:plan — create implementation plans
  • /ce:work — implement changes
  • /ce:brainstorm — explore approaches

Model: Opus · Max turns: 10

Scheduled triage

Runs weekdays at 12:00 PM Eastern. Finds open issues missing classification labels and triages up to 5 per run. Can also be triggered manually via workflow_dispatch.

Model: Sonnet · Max turns: 15

Typical Workflow

Here's how these pieces work together for a typical issue:

1. Someone creates an issue describing a bug
2. You add the "triage" label
3. Claude classifies it as "bug" + "scope:small" + "autofix-candidate"
4. You add the "fix" label
5. Claude implements the fix, runs tests, opens a PR
6. You review the PR (or ask @claude for a /ce:review)
7. Merge!

For complex issues, use solve to let Claude handle steps 2-5 autonomously.

Customization

Changing the target branch

The workflows default to targeting main for PRs. If you use a different branch (e.g., staging, develop), update the PR target references in ci-agent.yml.

Adjusting models and turn limits

Each job specifies its model and max turns in claude_args. Adjust based on your needs:

  • Sonnet — faster and cheaper, good for triage and small fixes
  • Opus — more capable, better for complex planning and implementation

Removing the Compound Engineering plugin

If you don't want to use the plugin, remove these two lines from each job:

plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"

And replace /ce:plan and /ce:work references in the prompts with generic instructions.

Removing Node.js setup

If your project doesn't use Node.js, remove the Setup Node step from the fix and solve jobs, and delete the actions/setup-node/ directory. Update the lint/test commands in the prompts accordingly.

Cost Control

  • Scope-aware model selection — mini/small issues use cheaper Sonnet; medium/large use Opus
  • Turn limits — each job has a max turn count to prevent runaway costs
  • Concurrency groups — re-labeling cancels in-progress runs
  • Scheduled triage limit — processes max 5 issues per run
  • Timeout limits — jobs are killed after their timeout (10-30 min)

License

MIT

name: CI Agent
on:
issues:
types: [labeled]
jobs:
# ============================================
# Triage — classify and scope the issue
# ============================================
triage:
if: github.event.label.name == 'triage'
runs-on: ubuntu-latest
timeout-minutes: 10
concurrency:
group: ci-agent-triage-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
contents: read
issues: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Triage Issue
uses: anthropics/claude-code-action@v1
with:
show_full_output: true
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"
prompt: |
Triage this GitHub issue:
**Title:** ${{ github.event.issue.title }}
**Body:** ${{ github.event.issue.body }}
**Issue Number:** #${{ github.event.issue.number }}
Steps:
1. Read the issue carefully
2. Review relevant parts of the codebase for context (check CLAUDE.md for architecture overview)
3. Classify it as one of: bug, feature, chore, or improvement
4. Estimate scope as one of:
- mini: trivial one-line or few-line change (typo, string fix, config value, route path)
- small: straightforward fix under 1 hour, limited files
- medium: 1-4 hours, touches multiple files or areas
- large: 4+ hours, significant feature or refactor
5. Determine if this is a candidate for automated fix (simple and well-scoped = yes)
6. Use the GitHub CLI to:
a. Apply the classification label (bug, feature, chore, or improvement)
b. Apply the scope label (scope:mini, scope:small, scope:medium, or scope:large)
c. If it's a good candidate for automated fix, apply the label: autofix-candidate
d. Remove the "triage" label since triage is now complete
7. Comment on the issue with a summary:
- Classification and reasoning
- Scope estimate and what drives it
- Which areas of the codebase are affected (specific files/directories)
- Whether this is a candidate for automated fix and why
claude_args: "--model claude-sonnet-4-6 --max-turns 8 --allowedTools Read Glob Grep 'Bash(gh:*)' 'Bash(ls:*)'"
# ============================================
# Plan — create implementation plan
# ============================================
plan:
if: github.event.label.name == 'plan'
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: ci-agent-plan-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build Plan
uses: anthropics/claude-code-action@v1
with:
show_full_output: true
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"
prompt: |
Read CLAUDE.md first for project conventions, architecture, and branch naming rules.
Use /ce:plan to create an implementation plan for this GitHub issue:
**Title:** ${{ github.event.issue.title }}
**Body:** ${{ github.event.issue.body }}
**Labels:** ${{ join(github.event.issue.labels.*.name, ', ') }}
**Issue Number:** #${{ github.event.issue.number }}
After the plan is created:
1. Create a branch: plan-${{ github.event.issue.number }}-<short-description> (dashes only, no slashes)
2. Save the plan to docs/plans/issue-${{ github.event.issue.number }}.md
3. Push and open a draft PR:
- Title with "docs:" prefix (to avoid triggering preview builds)
- Link to issue #${{ github.event.issue.number }} in the PR body
- Target the main branch
4. Use the GitHub CLI to:
a. Add the "planned" label to the issue
b. Remove the "plan" label since planning is complete
5. Comment on the issue with:
- A brief summary of the plan
- Link to the PR for full details
- Any open questions that need human input
claude_args: "--model claude-opus-4-6 --max-turns 15 --allowedTools Edit Read Write Glob Grep 'Bash(gh:*)' 'Bash(git:*)' 'Bash(ls:*)'"
# ============================================
# Fix — implement a targeted fix
# Scope-aware: uses Sonnet + fewer turns for small issues
# ============================================
fix:
if: github.event.label.name == 'fix'
runs-on: ubuntu-latest
timeout-minutes: 20
concurrency:
group: ci-agent-fix-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Determine scope config
id: config
run: |
LABELS="${{ join(github.event.issue.labels.*.name, ',') }}"
if [[ "$LABELS" == *"scope:mini"* ]]; then
echo "model=claude-sonnet-4-6" >> $GITHUB_OUTPUT
echo "max_turns=15" >> $GITHUB_OUTPUT
echo "scope=mini" >> $GITHUB_OUTPUT
elif [[ "$LABELS" == *"scope:small"* ]]; then
echo "model=claude-sonnet-4-6" >> $GITHUB_OUTPUT
echo "max_turns=15" >> $GITHUB_OUTPUT
echo "scope=small" >> $GITHUB_OUTPUT
elif [[ "$LABELS" == *"scope:large"* ]]; then
echo "model=claude-opus-4-6" >> $GITHUB_OUTPUT
echo "max_turns=30" >> $GITHUB_OUTPUT
echo "scope=large" >> $GITHUB_OUTPUT
else
echo "model=claude-opus-4-6" >> $GITHUB_OUTPUT
echo "max_turns=20" >> $GITHUB_OUTPUT
echo "scope=medium" >> $GITHUB_OUTPUT
fi
- name: Implement Fix
uses: anthropics/claude-code-action@v1
with:
show_full_output: true
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"
prompt: |
Read CLAUDE.md first for project conventions, architecture, and branch naming rules.
Fix this GitHub issue:
**Title:** ${{ github.event.issue.title }}
**Body:** ${{ github.event.issue.body }}
**Labels:** ${{ join(github.event.issue.labels.*.name, ', ') }}
**Issue Number:** #${{ github.event.issue.number }}
**Scope:** ${{ steps.config.outputs.scope }}
Check if a plan exists at docs/plans/issue-${{ github.event.issue.number }}.md — if so, follow it.
## Scope-based approach
If scope is **mini**: Make the change directly. Run `npm run lint`. Create a branch, commit, push, open a PR targeting main, remove the "fix" label, add "in-progress", and comment on the issue with what you changed and the PR link. Skip tests and confidence assessment — this is a trivial change.
If scope is **small**: Implement directly. Run lint and tests. Follow the full post-fix checklist below.
If scope is **medium** or **large**: Use /ce:work to implement systematically. Follow the full post-fix checklist below.
## Post-fix checklist (small/medium/large only)
1. Run the linter: npm run lint
2. Run relevant tests: npm test -- --run
3. Create a branch: fix-${{ github.event.issue.number }}-<short-description> (dashes only, no slashes)
4. Commit with a clear message, push, and open a PR:
- PR title should use "fix:" prefix
- Link to issue #${{ github.event.issue.number }} in the PR body
- Target the main branch
5. Assess your confidence level:
- HIGH: Changes are straightforward, tests pass, limited blast radius
- MEDIUM: Changes are reasonable but touch multiple areas
- LOW: Unsure about approach, tests inconclusive, or touching critical paths
6. If confidence is MEDIUM or LOW:
- Mark the PR as draft
- Add the "needs-review" label to the PR
- Clearly explain what needs human attention in the PR description
7. Use the GitHub CLI to:
a. Remove the "fix" label from the issue
b. Add the "in-progress" label to the issue
8. Comment on the issue with:
- What was changed and why
- Test results
- Confidence level and any caveats
- Link to the PR
Be conservative. If the fix touches critical paths or you are unsure, say so.
claude_args: "--model ${{ steps.config.outputs.model }} --max-turns ${{ steps.config.outputs.max_turns }} --allowedTools Edit Read Write Glob Grep 'Bash(gh:*)' 'Bash(git:*)' 'Bash(npm:*)' 'Bash(npx:*)' 'Bash(node:*)' 'Bash(ls:*)'"
# ============================================
# Solve — full end-to-end autonomous resolution
# ============================================
solve:
if: github.event.label.name == 'solve'
runs-on: ubuntu-latest
timeout-minutes: 30
concurrency:
group: ci-agent-solve-${{ github.event.issue.number }}
cancel-in-progress: true
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: ./.github/actions/setup-node
- name: Solve Issue End-to-End
uses: anthropics/claude-code-action@v1
with:
show_full_output: true
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"
prompt: |
Read CLAUDE.md first for project conventions, architecture, and branch naming rules.
Solve this GitHub issue end-to-end:
**Title:** ${{ github.event.issue.title }}
**Body:** ${{ github.event.issue.body }}
**Issue Number:** #${{ github.event.issue.number }}
## Phase 1: TRIAGE
1. Read the issue carefully
2. Review relevant parts of the codebase
3. Classify as: bug, feature, chore, or improvement
4. Estimate scope: mini (trivial one-liner), small, medium, or large
5. Apply the classification and scope labels via GitHub CLI
## Phase 2: PLAN
If scope is mini, skip planning — go straight to Phase 3.
Otherwise, use /ce:plan to create an implementation plan.
Save the plan to docs/plans/issue-${{ github.event.issue.number }}.md
## Phase 3: IMPLEMENT
If scope is mini or small, implement directly.
If scope is medium or large, use /ce:work to implement the plan.
1. Run the linter: npm run lint
2. Run relevant tests: npm test -- --run
3. Fix any lint or test failures before proceeding
## Phase 4: DELIVER
1. Create a branch following the naming convention (dashes only, no slashes):
- Bug fix: fix-${{ github.event.issue.number }}-<short-description>
- Feature: feat-${{ github.event.issue.number }}-<short-description>
- Chore: chore-${{ github.event.issue.number }}-<short-description>
2. Commit all changes with a clear message
3. Push and open a PR:
- Use the appropriate title prefix (feat:, fix:, chore:)
- Link to issue #${{ github.event.issue.number }} in the PR body
- Target the main branch
## Phase 5: ASSESS & REPORT
1. Assess your confidence level:
- HIGH: Straightforward, tests pass, limited blast radius
- MEDIUM: Reasonable but touches multiple areas
- LOW: Unsure about approach, tests inconclusive, or touching critical paths
2. If confidence is MEDIUM or LOW:
- Mark the PR as draft
- Add the "needs-review" label to the PR
- Clearly explain what needs human attention
3. Use the GitHub CLI to:
a. Remove the "solve" label from the issue
b. Add the "in-progress" label to the issue
4. Comment on the issue with a full summary:
- Classification and scope
- What was planned
- What was implemented
- Lint and test results
- Confidence level and any caveats
- Link to the PR
claude_args: "--model claude-opus-4-6 --max-turns 35 --allowedTools Edit Read Write Glob Grep 'Bash(gh:*)' 'Bash(git:*)' 'Bash(npm:*)' 'Bash(npx:*)' 'Bash(node:*)' 'Bash(ls:*)'"
name: Claude
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
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'))
runs-on: ubuntu-latest
timeout-minutes: 30
concurrency:
group: claude-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Claude
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
show_full_output: true
claude_args: "--model claude-opus-4-6 --max-turns 10 --allowedTools Edit Read Write Glob Grep 'Bash(gh:*)' 'Bash(git:*)' 'Bash(npm:*)' 'Bash(ls:*)'"
plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"
prompt: |
You have access to /ce: slash commands from the compound-engineering plugin.
Use them when appropriate:
- /ce:review for code review requests on PRs
- /ce:plan for planning implementation of issues
- /ce:work for implementing changes
- /ce:brainstorm for exploring approaches
Always read CLAUDE.md first for project conventions.
name: Scheduled Triage
on:
schedule:
# Run Monday through Friday at 16:00 UTC (12:00 PM Eastern)
- cron: "0 16 * * 1-5"
workflow_dispatch: # Allow manual trigger
jobs:
triage-untriaged:
runs-on: ubuntu-latest
timeout-minutes: 30
concurrency:
group: scheduled-triage
cancel-in-progress: true
permissions:
contents: read
issues: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Find and Triage Untriaged Issues
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
plugin_marketplaces: "https://github.com/EveryInc/compound-engineering-plugin.git"
plugins: "compound-engineering@compound-engineering-plugin"
prompt: |
You are running as a scheduled job. Your task is to find and triage
any GitHub issues that haven't been triaged yet.
Steps:
1. Use the GitHub CLI to list open issues that do NOT have any of these labels:
bug, feature, chore, improvement, triage, planned, in-progress, solve
Command: gh issue list --state open --json number,title,body,labels --limit 20
2. Filter to only issues missing classification labels
3. For each untriaged issue (up to 5 per run to control costs):
a. Read the issue carefully
b. Review relevant parts of the codebase
c. Classify as: bug, feature, chore, or improvement
d. Estimate scope: mini (trivial one-liner), small, medium, or large
e. Apply the classification and scope labels (scope:mini, scope:small, scope:medium, or scope:large)
f. If it's a good candidate for automated fix, apply: autofix-candidate
g. Comment with your triage summary
4. If there are no untriaged issues, do nothing (no comment needed)
Read CLAUDE.md first for project context and architecture.
Be thorough but concise in your triage comments.
show_full_output: true
claude_args: "--model claude-sonnet-4-6 --max-turns 15 --allowedTools 'Bash(gh:*)'"
name: Setup Node.js
description: Install Node.js from .nvmrc and restore cached node_modules
runs:
using: composite
steps:
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Cache node_modules
id: cache-deps
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- name: Install Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
shell: bash
run: npm ci
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment