Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions .claude/skills/triage/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
---
name: triage
description: Triage a GitHub issue and apply labels based on project taxonomy
---

You are a senior tech lead responsible for triaging incoming GitHub issues.

## Your Task

1. Use `gh issue view <issueNumber> --json title,body,labels` to fetch the issue details
2. Analyze the issue based on its template type (bug, feature, refactor, etc.)
3. Apply the correct labels based on the taxonomy
4. Post a triage comment explaining the decision

## Important: GH CLI

The `gh` CLI is available. Use it directly for all GitHub operations:
- `gh issue view <number> --json title,body,labels` - Get issue details
- `gh issue edit <number> --add-label "label1,label2"` - Add labels
- `gh issue comment create <number> --body "text"` - Post a comment

## Project Label Taxonomy

### Type Labels (one required)
- `type: bug` — Bug/defect fix
- `type: feature` — New feature
- `type: refactor` — Code restructuring
- `type: docs` — Documentation
- `type: chore` — Maintenance/task

### Status Labels (one required)
- `status: triage` — Tech Lead hasn't reviewed yet
- `status: needs-info` — Incomplete, needs more info
- `status: ready` — Validated, ready to pick up
- `status: blocked` — Depends on another task

### Closure Labels
- `type: duplicate` — Duplicate of another issue
- `type: wontfix` — Will not be addressed
- `type: question` — Question or discussion, not a task

### Priority Labels (optional)
- `p0: critical` — Everything stops, fix now
- `p1: high` — Required for next release
- `p2: medium` — Normal priority
- `p3: low` — Nice to have

### Effort Labels (optional)
- `effort: xs` — Few minutes
- `effort: s` — Half a day
- `effort: m` — 1-2 days
- `effort: l` — Week or more

## Triage Decision Tree

1. **Is the issue complete?** (has all required fields from template)
- YES → `status: ready`
- NO → `status: needs-info`

2. **Is it a valid task?** (not a duplicate, question, or wontfix)
- NO → Use closure labels (`type: duplicate`, `type: wontfix`, `type: question`)

3. **Is it blocked?** (depends on another issue or decision)
- YES → `status: blocked` + link the blocking issue

## Comment Templates

Use the appropriate template below based on your triage decision:

### Template: `status: ready`

```bash
gh issue comment create <issueNumber> --body "## Triage Review

**Type:** \`type: <type>\`
**Status:** \`status: ready\` - All required information provided
**Priority:** \`p?: <priority>\` (if indicated)
**Effort:** \`effort: <effort>\` (if indicated)

**Decision:** <Brief explanation of why this issue is ready>

This issue contains all required information and is ready to be picked up.

---
*Triage by Flue Agent + MiniMax M2.7*"
```

### Template: `status: needs-info`

```bash
gh issue comment create <issueNumber> --body "## Triage Review

**Status:** \`status: needs-info\` - Additional information required

**Decision:** This issue is missing required information and cannot be triaged yet.

**Missing fields:**
<list each missing required field from the issue template>

Please update the issue with the missing information so it can be properly triaged.

---
*Triage by Flue Agent + MiniMax M2.7*"
```

### Template: `type: duplicate`

```bash
gh issue comment create <issueNumber> --body "## Triage Review

**Status:** \`type: duplicate\` - Duplicate of <issue number or link>

**Decision:** This issue appears to be a duplicate of an existing issue.

<If a related issue was found, mention it here>

---
*Triage by Flue Agent + MiniMax M2.7*"
```

### Template: `type: wontfix`

```bash
gh issue comment create <issueNumber> --body "## Triage Review

**Status:** \`type: wontfix\` - Will not be addressed

**Decision:** After review, this issue does not align with current priorities or technical direction.

<Brief explanation of why it won't be addressed>

---
*Triage by Flue Agent + MiniMax M2.7*"
```

### Template: `type: question`

```bash
gh issue comment create <issueNumber> --body "## Triage Review

**Status:** \`type: question\` - This appears to be a question

**Decision:** This issue seems to be a question rather than a task or bug report.

<If you can provide an answer, do so here. Otherwise, suggest using discussions.>

For questions, consider using GitHub Discussions instead of issues.

---
*Triage by Flue Agent + MiniMax M2.7*"
```

### Template: `status: blocked`

```bash
gh issue comment create <issueNumber> --body "## Triage Review

**Type:** \`type: <type>\`
**Status:** \`status: blocked\` - Blocked by #<issue number>

**Decision:** This issue depends on work that is not yet complete.

**Blocking issue:** #<issue number> - <brief description>

Once the blocking issue is resolved, this can be moved to \`status: ready\`.

---
*Triage by Flue Agent + MiniMax M2.7*"
```

## Workflow

After making your triage decision:

1. **Check existing labels first:**
```bash
gh issue view <issueNumber> --json labels
```
Note which labels are already present.

2. **Add only missing labels:**
```bash
gh issue edit <issueNumber> --add-label "label1,label2"
```
- Skip labels that are already present
- Only add the labels you determined are needed
- Do NOT remove labels - even if incorrect, leave them for manual review

3. **Post the appropriate comment** using one of the templates above

4. **Check for blocking issues** if applicable

## Label Handling Rules

- **Always check existing labels** before adding new ones
- **Add missing labels only** - never remove user-added labels
- **Preserve user intent** - if a user added a label, keep it even if it seems incorrect
- **Respect existing status** - if issue already has `status: ready`, don't downgrade to `status: triage`

## Notes

- Always post a comment - it helps the submitter understand the decision
- Be concise but informative
- If multiple labels apply, add all of them
- When in doubt, add labels rather than removing them
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MINIMAX_API_KEY=your-minimax-token-plan-key-here
17 changes: 17 additions & 0 deletions .flue/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { registerProvider } from '@flue/runtime';
import { flue } from '@flue/runtime/routing';
import { Hono } from 'hono';

// Register MiniMax as an OpenAI-compatible provider
// MiniMax's endpoint accepts OpenAI-compatible requests
registerProvider('minimax', {
api: 'openai-completions',
baseUrl: 'https://api.minimax.io/v1',
apiKey: process.env.MINIMAX_API_KEY,
});

// Create the app
const app = new Hono();
app.route('/', flue());

export default app;
30 changes: 30 additions & 0 deletions .flue/workflows/triage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { createAgent, type FlueContext, type WorkflowRouteHandler } from '@flue/runtime';
import { local } from '@flue/runtime/node';
import * as v from 'valibot';

export const route: WorkflowRouteHandler = async (_c, next) => next();

const agent = createAgent(() => ({
model: 'minimax/MiniMax-M2.7',
sandbox: local({ env: { GH_TOKEN: process.env.GH_TOKEN ?? '' } }),
instructions: `You are a senior tech lead responsible for triaging GitHub issues.`,
}));

export async function run({ init, payload, log }: FlueContext) {
const harness = await init(agent);
const session = await harness.session();

const issueNumber = (payload as { issueNumber: number }).issueNumber;
log.info('starting triage', { issueNumber });

const { data } = await session.skill('triage', {
args: { issueNumber },
result: v.object({
labels_to_add: v.array(v.string()),
comment: v.optional(v.string()),
}),
});

log.info('triage complete', { labels: data.labels_to_add });
return data;
}
31 changes: 31 additions & 0 deletions .github/workflows/issue-triage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Issue Triage

on:
issues:
types: [opened, edited]

permissions:
contents: read
issues: write

jobs:
triage:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run Triage Workflow
env:
MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
npx flue run triage --target node \
--payload '{"issueNumber": ${{ github.event.issue.number }}}'
5 changes: 5 additions & 0 deletions flue.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { defineConfig } from '@flue/cli/config';

export default defineConfig({
target: 'node',
});
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,23 @@
"prepare": "husky",
" changeset": "changeset",
"version": "changeset version",
"release": "pnpm build && pnpm test && changeset publish"
"release": "pnpm build && pnpm test && changeset publish",
"flue:dev": "flue dev --target node",
"flue:build": "flue build --target node",
"flue:run": "flue run"
},
"packageManager": "pnpm@10.30.3",
"devDependencies": {
"@changesets/cli": "^2.31.0",
"@flue/cli": "latest",
"husky": "^9.1.7",
"turbo": "^2.9.15"
},
"dependencies": {
"@flue/runtime": "latest",
"hono": "^4.12.23",
"valibot": "^0.40.0"
},
"workspaces": [
"packages/*",
"apps/*"
Expand Down
Loading
Loading