Skip to content

fix: Enable batch mode for issue triage safe-outputs#10775

Merged
stnguyen90 merged 10 commits intomainfrom
fix/issue-triage-batch-mode
Nov 13, 2025
Merged

fix: Enable batch mode for issue triage safe-outputs#10775
stnguyen90 merged 10 commits intomainfrom
fix/issue-triage-batch-mode

Conversation

@stnguyen90
Copy link
Copy Markdown
Contributor

What does this PR do?

The new issue triage workflow ran, but it didn't create any issues or applied any labels:

image

To fix this:

  • Add target: "*" to safe-outputs configuration for add-labels and add-comment
  • This allows the workflow to apply comments and labels to multiple issues when running in scheduled/manual trigger mode (batch processing)
  • Previously, safe-outputs jobs were skipped because they required github.event.issue.number which only exists in event-triggered runs
  • With target: "*", the workflow now reads issue numbers from the agent output and applies changes to each issue individually

Test Plan

Manual

Related PRs and Issues

None

Checklist

  • Have you read the Contributing Guidelines on issues?
  • If the PR includes a change to an API's metadata (desc, label, params, etc.), does it also include updated API specs and example docs?

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 6, 2025

📝 Walkthrough

Walkthrough

This PR updates the issue-triage GitHub Actions workflow and accompanying docs and JS helpers. Changes include actions/upload-artifact v4→v5 and Copilot CLI v0.0.353→0.0.354, added COPILOT_GITHUB_TOKEN support, GH_AW_ERROR_PATTERNS for log parsing, staged-preview support for add-comment/add-labels, expanded safe-outputs limits and wildcard targets, improved path/branch/PR handling and env fallbacks, reworked prompt/template interpolation and conditionals, expanded redaction/threat-detection and log parsing (new runLogParser export), and several new/expanded module exports and MCP/tooling exposure. Workflow conditionals and summary formatting were also revised.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Workflow YAML: action bumps, env additions (GH_AW_ERROR_PATTERNS, COPILOT_GITHUB_TOKEN), path quoting, conditional logic, staged-preview job changes.
  • Agent/Copilot code: token validation changes, version bump, expanded redaction and threat-detection logic.
  • Prompt/template and triage logic: interpolation, conditionals, prompt guidance changes, and triage criteria (24h updated_at).
  • New/expanded exports: runLogParser and multiple formatting/parsing helpers — verify public API surface and tests.
  • MCP/server and mcp-config exposure changes.

Files/areas to inspect closely:

  • .github/workflows/issue-triage.lock.yml and .github/workflows/issue-triage.md
  • Agent/Copilot token handling and redaction modules (token validation, sanitization, log parsing)
  • Prompt/template rendering and staged-preview implementation
  • Modules where new exports were added (threat-detection/parsing and formatter utilities)

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: enabling batch mode for issue triage safe-outputs configuration.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation, fix, and test plan for enabling batch processing in the issue triage workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-triage-batch-mode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 6, 2025

Security Scan Results for PR

Docker Image Scan Results

Package Version Vulnerability Severity
binutils 2.44-r2 CVE-2025-5244 HIGH
binutils 2.44-r2 CVE-2025-5245 HIGH
libxml2 2.13.8-r0 CVE-2025-49794 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49796 CRITICAL
libxml2 2.13.8-r0 CVE-2025-49795 HIGH
libxml2 2.13.8-r0 CVE-2025-6021 HIGH
pcre2 10.43-r1 CVE-2025-58050 CRITICAL
github.com/containerd/containerd/v2 v2.0.2 CVE-2024-25621 HIGH
golang.org/x/crypto v0.31.0 CVE-2025-22869 HIGH
golang.org/x/oauth2 v0.24.0 CVE-2025-22868 HIGH
stdlib 1.22.10 CVE-2025-47907 HIGH
stdlib 1.22.10 CVE-2025-58183 HIGH
stdlib 1.22.10 CVE-2025-58186 HIGH
stdlib 1.22.10 CVE-2025-58187 HIGH
stdlib 1.22.10 CVE-2025-58188 HIGH

Source Code Scan Results

🎉 No vulnerabilities found!

- Add target: "*" to safe-outputs configuration for add-labels and add-comment
- This allows the workflow to apply comments and labels to multiple issues
  when running in scheduled/manual trigger mode (batch processing)
- Previously, safe-outputs jobs were skipped because they required
  github.event.issue.number which only exists in event-triggered runs
- With target: "*", the workflow now reads issue numbers from the agent
  output and applies changes to each issue individually
@stnguyen90 stnguyen90 force-pushed the fix/issue-triage-batch-mode branch from cf3f8fb to 2f255ce Compare November 6, 2025 19:50
@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 6, 2025

✨ Benchmark results

  • Requests per second: 1,203
  • Requests with 200 status code: 216,676
  • P99 latency: 0.16325743

⚡ Benchmark Comparison

Metric This PR Latest version
RPS 1,203 1,193
200 216,676 214,862
P99 0.16325743 0.17270728

- Replace 'gh label list' bash command instruction with 'list_labels' GitHub MCP tool
- GitHub MCP tools are already enabled and authenticated, no additional config needed
- Fixes permission denied errors when agent tried to use gh CLI
The correct tool name in GitHub MCP server is 'list_label' (singular), not 'list_labels' (plural). This was causing the agent to fall back to bash commands like 'gh label list' instead of using the proper MCP tool.
- Add github tool configuration with 'default' and 'labels' toolsets
- The labels toolset was not enabled by default, causing the agent
  to fall back to bash commands like 'gh label list'
- Now list_label MCP tool will be available to the agent
@stnguyen90 stnguyen90 marked this pull request as ready for review November 6, 2025 23:54
@stnguyen90 stnguyen90 requested a review from EVDOG4LIFE November 6, 2025 23:54
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/issue-triage.md (1)

83-89: Fix tool mismatch: use add_labels (not update_issue) for labels.

Your jobs process add_labels outputs, not update_issue. Instructing the agent to use update_issue will be ignored by the workflow.

Apply:

-   - Use the `update_issue` tool to apply the labels to the issue
+   - Use the `add_labels` tool to apply the labels to the issue
.github/workflows/issue-triage.lock.yml (1)

2250-2266: Correct tool names in prompt section.

The safe-outputs tools are add_comment, add_labels, and missing_tool. Current text uses hyphenated/plural names that don’t exist and can mislead the agent.

Apply:

- To add a comment ... use the add-comments tool from safeoutputs
+ To add a comment ... use the add_comment tool from safeoutputs
- To add labels ... use the add-labels tool from safeoutputs
+ To add labels ... use the add_labels tool from safeoutputs
- To report a missing tool use the missing-tool tool from safeoutputs.
+ To report a missing tool use the missing_tool tool from safeoutputs.
🧹 Nitpick comments (2)
.github/workflows/issue-triage.md (1)

54-56: Grammar nit: “generated by a bot”.

Apply:

-If the issue is obviously spam, or generated by bot, or something else that is not an actual issue...
+If the issue is obviously spam, or generated by a bot, or something else that is not an actual issue...
.github/workflows/issue-triage.lock.yml (1)

2144-2153: Align prompt guidance with tool usage for labels.

Prompt still says “Use the update_issue tool to apply the labels” (compiled from the MD). Change to add_labels to match the job that executes label changes.

Update prompt source (MD) and recompile so the generated prompt reflects add_labels.

Also applies to: 2175-2193

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebee879 and 84ebbc6.

📒 Files selected for processing (2)
  • .github/workflows/issue-triage.lock.yml (39 hunks)
  • .github/workflows/issue-triage.md (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/issue-triage.lock.yml

75-75: label "ubuntu-slim" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

🪛 LanguageTool
.github/workflows/issue-triage.md

[uncategorized] ~54-~54: Possible missing article found.
Context: ...ssue is obviously spam, or generated by bot, or something else that is not an actua...

(AI_HYDRA_LEO_MISSING_A)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Databases/Legacy)
🔇 Additional comments (3)
.github/workflows/issue-triage.lock.yml (3)

541-542: Good: wildcard targets wired for batch mode.

GH_AW_COMMENT_TARGET="*" and GH_AW_LABELS_TARGET="*" allow reading targets from agent outputs. Once the max and label loop issues are fixed, batch should work end-to-end.

Also applies to: 931-932


62-69: Stricter error pattern env looks solid.

Regexes cover GH workflow commands, bracketed levels, and timestamped Copilot logs; sensible for detection without false positives.


75-81: ****

The ubuntu-slim runner label is valid and supported by GitHub-hosted runners as of 2025. It is a single-CPU, container-based runner listed in GitHub's official runner tables, and no changes are needed to the workflow file.

Likely an incorrect or invalid review comment.

Comment on lines +1001 to 1031
const result = loadAgentOutput();
if (!result.success) {
return;
}
const labelsItem = validatedOutput.items.find(item => item.type === "add_labels");
const labelsItem = result.items.find(item => item.type === "add_labels");
if (!labelsItem) {
core.warning("No add-labels item found in agent output");
return;
}
core.info(`Found add-labels item with ${labelsItem.labels.length} labels`);
if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
let summaryContent = "## 🎭 Staged Mode: Add Labels Preview\n\n";
summaryContent += "The following labels would be added if staged mode was disabled:\n\n";
if (labelsItem.item_number) {
summaryContent += `**Target Issue:** #${labelsItem.item_number}\n\n`;
} else {
summaryContent += `**Target:** Current issue/PR\n\n`;
}
if (labelsItem.labels && labelsItem.labels.length > 0) {
summaryContent += `**Labels to add:** ${labelsItem.labels.join(", ")}\n\n`;
}
await core.summary.addRaw(summaryContent).write();
core.info("📝 Label addition preview written to step summary");
await generateStagedPreview({
title: "Add Labels",
description: "The following labels would be added if staged mode was disabled:",
items: [labelsItem],
renderItem: item => {
let content = "";
if (item.item_number) {
content += `**Target Issue:** #${item.item_number}\n\n`;
} else {
content += `**Target:** Current issue/PR\n\n`;
}
if (item.labels && item.labels.length > 0) {
content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
}
return content;
},
});
return;
}
const allowedLabelsEnv = process.env.GH_AW_LABELS_ALLOWED?.trim();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Process all add_labels items, not just the first.

Current code uses .find(...), so only one label action is applied. Switch to .filter(...) and iterate, respecting per-item targets and max count per item.

Apply:

- const labelsItem = result.items.find(item => item.type === "add_labels");
- if (!labelsItem) {
+ const labelItems = result.items.filter(item => item.type === "add_labels");
+ if (labelItems.length === 0) {
   core.warning("No add-labels item found in agent output");
   return;
 }
- core.info(`Found add-labels item with ${labelsItem.labels.length} labels`);
+ core.info(`Found ${labelItems.length} add-labels item(s)`);

- if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
-   await generateStagedPreview({
-     title: "Add Labels",
-     description: "The following labels would be added if staged mode was disabled:",
-     items: [labelsItem],
-     renderItem: item => {
-       let content = "";
-       if (item.item_number) {
-         content += `**Target Issue:** #${item.item_number}\n\n`;
-       } else {
-         content += `**Target:** Current issue/PR\n\n`;
-       }
-       if (item.labels && item.labels.length > 0) {
-         content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
-       }
-       return content;
-     },
-   });
-   return;
- }
+ if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
+   await generateStagedPreview({
+     title: "Add Labels",
+     description: "The following labels would be added if staged mode was disabled:",
+     items: labelItems,
+     renderItem: item => {
+       let content = "";
+       if (item.item_number) content += `**Target Issue:** #${item.item_number}\n\n`;
+       else content += `**Target:** Current issue/PR\n\n`;
+       if (item.labels?.length) content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
+       return content;
+     },
+   });
+   return;
+ }
 
- const labelsTarget = process.env.GH_AW_LABELS_TARGET || "triggering";
+ const labelsTarget = process.env.GH_AW_LABELS_TARGET || "triggering";
  core.info(`Labels target configuration: ${labelsTarget}`);
 
- let itemNumber;
- let contextType;
- if (labelsTarget === "*") {
-   if (labelsItem.item_number) {
-     itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
-     ...
-   }
- } else if (labelsTarget && labelsTarget !== "triggering") {
-   ...
- } else {
-   ...
- }
- if (!itemNumber) { core.setFailed("Could not determine issue or pull request number"); return; }
- const requestedLabels = labelsItem.labels || [];
- ...
- await github.rest.issues.addLabels({ issue_number: itemNumber, labels: uniqueLabels })
+ for (const labelsItem of labelItems) {
+   let itemNumber;
+   let contextType;
+   if (labelsTarget === "*") {
+     if (labelsItem.item_number) {
+       itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
+       if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`); continue; }
+       contextType = "issue";
+     } else {
+       core.setFailed('Target is "*" but no item_number specified in labels item');
+       continue;
+     }
+   } else if (labelsTarget && labelsTarget !== "triggering") {
+     itemNumber = parseInt(labelsTarget, 10);
+     if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`); continue; }
+     contextType = "issue";
+   } else {
+     // triggering context fallback (issue/PR), same as existing code...
+     if (context.payload.issue) { itemNumber = context.payload.issue.number; contextType = "issue"; }
+     else if (context.payload.pull_request) { itemNumber = context.payload.pull_request.number; contextType = "pull request"; }
+     else { core.setFailed("Could not determine issue or pull request number"); continue; }
+   }
+
+   const requestedLabels = labelsItem.labels || [];
+   // existing validation/sanitization logic unchanged...
+   // ...
+   await github.rest.issues.addLabels({
+     owner: context.repo.owner,
+     repo: context.repo.repo,
+     issue_number: itemNumber,
+     labels: uniqueLabels,
+   });
+ }

Also applies to: 1049-1105, 1144-1169

Comment on lines 1272 to 1273
{"add_comment":{"max":1,"target":"*"},"add_labels":{"max":5},"missing_tool":{}}
EOF
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Batch comments blocked: add_comment max is 1 in safe-outputs MCP config.

This enforces at most one comment item during ingestion, defeating batch mode.

Regenerate lock after changing the source .md to include a higher max (e.g., max: 50) for add-comment, or update this generated config accordingly.

🤖 Prompt for AI Agents
.github/workflows/issue-triage.lock.yml around lines 1272-1273: the generated
config sets "add_comment":{"max":1,...} which prevents batch comments; update
the generated lock so the "max" for add_comment is increased (e.g., set max: 50)
and then regenerate the lock file from the source .md (or update the generator
output) so the workflow reflects the higher limit for add_comment.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/issue-triage.md (1)

86-89: Incorrect tool: use add_labels, not update_issue, for labeling.

Agents will emit update_issue items which are rejected by the safe-outputs config. Replace with add_labels and recompile.

Apply:

-   - Use the `update_issue` tool to apply the labels to the issue
+   - Use the `add_labels` tool to apply the labels to the issue
.github/workflows/issue-triage.lock.yml (1)

2144-2181: Prompt still tells agents to use update_issue for labels (generated).

Regenerate lock after fixing the source md, or patch here if necessary before compile.

-             - Use the `update_issue` tool to apply the labels to the issue
+             - Use the `add_labels` tool to apply the labels to the issue
♻️ Duplicate comments (1)
.github/workflows/issue-triage.lock.yml (1)

1001-1031: add_labels processes only the first item; iterate all to enable true batch mode.

Current code uses .find(...) and never loops, so only one labels item is applied. Replace with .filter(...) and iterate, including staged preview. This blocks batch labeling.

-              const labelsItem = result.items.find(item => item.type === "add_labels");
-              if (!labelsItem) {
+              const labelItems = result.items.filter(item => item.type === "add_labels");
+              if (labelItems.length === 0) {
                 core.warning("No add-labels item found in agent output");
                 return;
               }
-              core.info(`Found add-labels item with ${labelsItem.labels.length} labels`);
+              core.info(`Found ${labelItems.length} add-labels item(s)`);
               if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
                 await generateStagedPreview({
                   title: "Add Labels",
                   description: "The following labels would be added if staged mode was disabled:",
-                  items: [labelsItem],
-                  renderItem: item => {
+                  items: labelItems,
+                  renderItem: item => {
                     let content = "";
                     if (item.item_number) {
                       content += `**Target Issue:** #${item.item_number}\n\n`;
                     } else {
                       content += `**Target:** Current issue/PR\n\n`;
                     }
                     if (item.labels && item.labels.length > 0) {
                       content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
                     }
                     return content;
                   },
                 });
                 return;
               }
@@
-              let itemNumber;
-              let contextType;
-              if (labelsTarget === "*") {
-                if (labelsItem.item_number) {
-                  itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
-                  if (isNaN(itemNumber) || itemNumber <= 0) {
-                    core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`);
-                    return;
-                  }
-                  contextType = "issue";
-                } else {
-                  core.setFailed('Target is "*" but no item_number specified in labels item');
-                  return;
-                }
-              } else if (labelsTarget && labelsTarget !== "triggering") {
-                itemNumber = parseInt(labelsTarget, 10);
-                if (isNaN(itemNumber) || itemNumber <= 0) {
-                  core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`);
-                  return;
-                }
-                contextType = "issue";
-              } else {
-                if (isIssueContext) {
-                  if (context.payload.issue) {
-                    itemNumber = context.payload.issue.number;
-                    contextType = "issue";
-                  } else {
-                    core.setFailed("Issue context detected but no issue found in payload");
-                    return;
-                  }
-                } else if (isPRContext) {
-                  if (context.payload.pull_request) {
-                    itemNumber = context.payload.pull_request.number;
-                    contextType = "pull request";
-                  } else {
-                    core.setFailed("Pull request context detected but no pull request found in payload");
-                    return;
-                  }
-                }
-              }
-              if (!itemNumber) {
-                core.setFailed("Could not determine issue or pull request number");
-                return;
-              }
-              const requestedLabels = labelsItem.labels || [];
+              for (const labelsItem of labelItems) {
+                let itemNumber;
+                let contextType;
+                if (labelsTarget === "*") {
+                  if (labelsItem.item_number) {
+                    itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
+                    if (isNaN(itemNumber) || itemNumber <= 0) {
+                      core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`);
+                      continue;
+                    }
+                    contextType = "issue";
+                  } else {
+                    core.setFailed('Target is "*" but no item_number specified in labels item');
+                    continue;
+                  }
+                } else if (labelsTarget && labelsTarget !== "triggering") {
+                  itemNumber = parseInt(labelsTarget, 10);
+                  if (isNaN(itemNumber) || itemNumber <= 0) {
+                    core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`);
+                    continue;
+                  }
+                  contextType = "issue";
+                } else {
+                  if (isIssueContext && context.payload.issue) {
+                    itemNumber = context.payload.issue.number;
+                    contextType = "issue";
+                  } else if (isPRContext && context.payload.pull_request) {
+                    itemNumber = context.payload.pull_request.number;
+                    contextType = "pull request";
+                  } else {
+                    core.setFailed("Could not determine issue or pull request number");
+                    continue;
+                  }
+                }
+                const requestedLabels = labelsItem.labels || [];
                 core.info(`Requested labels: ${JSON.stringify(requestedLabels)}`);
                 for (const label of requestedLabels) {
                   if (label && typeof label === "string" && label.startsWith("-")) {
                     core.setFailed(`Label removal is not permitted. Found line starting with '-': ${label}`);
-                    return;
+                    continue;
                   }
                 }
                 let validLabels;
                 if (allowedLabels) {
                   validLabels = requestedLabels.filter(label => allowedLabels.includes(label));
                 } else {
                   validLabels = requestedLabels;
                 }
                 let uniqueLabels = validLabels
                   .filter(label => label != null && label !== false && label !== 0)
                   .map(label => String(label).trim())
                   .filter(label => label)
                   .map(label => sanitizeLabelContent(label))
                   .filter(label => label)
                   .map(label => (label.length > 64 ? label.substring(0, 64) : label))
                   .filter((label, index, arr) => arr.indexOf(label) === index);
                 if (uniqueLabels.length > maxCount) {
                   core.info(`too many labels, keep ${maxCount}`);
                   uniqueLabels = uniqueLabels.slice(0, maxCount);
                 }
                 if (uniqueLabels.length === 0) {
                   core.info("No labels to add");
-                  core.setOutput("labels_added", "");
-                  await core.summary.addRaw(`\n## Label Addition\nNo labels were added (no valid labels found in agent output).\n`).write();
-                  return;
+                  continue;
                 }
                 core.info(`Adding ${uniqueLabels.length} labels to ${contextType} #${itemNumber}: ${JSON.stringify(uniqueLabels)}`);
                 try {
                   await github.rest.issues.addLabels({
                     owner: context.repo.owner,
                     repo: context.repo.repo,
                     issue_number: itemNumber,
                     labels: uniqueLabels,
                   });
                   core.info(`Successfully added ${uniqueLabels.length} labels to ${contextType} #${itemNumber}`);
-                  core.setOutput("labels_added", uniqueLabels.join("\n"));
                   const labelsListMarkdown = uniqueLabels.map(label => `- \`${label}\``).join("\n");
                   await core.summary.addRaw(`\n## Label Addition\nSuccessfully added ${uniqueLabels.length} label(s) to ${contextType} #${itemNumber}:\n${labelsListMarkdown}\n`).write();
                 } catch (error) {
                   const errorMessage = error instanceof Error ? error.message : String(error);
                   core.error(`Failed to add labels: ${errorMessage}`);
-                  core.setFailed(`Failed to add labels: ${errorMessage}`);
+                  // continue to next item
                 }
+              }

Also applies to: 1113-1169

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84ebbc6 and b1e6572.

📒 Files selected for processing (2)
  • .github/workflows/issue-triage.lock.yml (39 hunks)
  • .github/workflows/issue-triage.md (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/issue-triage.lock.yml

75-75: label "ubuntu-slim" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

🪛 LanguageTool
.github/workflows/issue-triage.md

[grammar] ~55-~55: Use a hyphen to join words.
Context: ...an issue comment to the issue with a one sentence analysis and move to the next i...

(QB_NEW_EN_HYPHEN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Locale)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Storage)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E General Test
  • GitHub Check: Unit Test
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (8)
.github/workflows/issue-triage.md (3)

24-30: Batch config enabled; confirm expected batch size.

Explicit max and target "*" look good for batch runs. If you expect >10 comments per run, consider raising add-comment max (e.g., 50) before compiling.


11-20: Stricter error pattern env is fine.

No issues; matches usage in lock.


59-60: Switch to list_label is correct.

Aligns with the GitHub MCP tools; no further changes needed.

.github/workflows/issue-triage.lock.yml (5)

62-69: Env GH_AW_ERROR_PATTERNS in lock is consistent.

Matches the source; OK.


1272-1273: Safe-outputs collector now allows add_comment max:10 and target:"*".

This unblocks multiple comments; in line with the md. Recompile after any md changes.


503-544: add_comment job correctly batches items and targets "*".

Filter + loop implemented; target env wired. Good.


931-932: Labels target set to "*" via env.

Correct for scheduled/manual contexts lacking github.event.issue.number.


75-81: The review comment is based on incorrect information.

"ubuntu-slim" is a valid GitHub-hosted runner label per official GitHub documentation. The code requires no changes. The runner label is correctly specified and actionlint should not flag it as invalid.

Likely an incorrect or invalid review comment.

- look for duplicate issues across the org
- fix deprecated timeout_minutes
- Include issues updated in last 24 hours (with new comments), not just newly created
- Add non-English content check: detect and request English translation respectfully
- Add multi-topic detection: ask users to split issues with multiple unrelated topics
- Improve spam detection with clear guidance
- Enhanced with empathetic approach for language and topic guidance
- Add parameter hints for list_label tool usage
- Clarify good first issue label application criteria
- Update summary message to reflect new triage scope
The list_issues tool's 'since' parameter already filters by updated_at,
which captures both newly created issues AND recently commented issues in
a single query. Removed redundant second query.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
.github/workflows/issue-triage.lock.yml (1)

1001-1171: Blocker: Process all add_labels items, not just the first (breaks batch mode).

The code still uses .find(...) and applies labels once. In batch runs with multiple add_labels entries, only the first is processed. Iterate all add_labels items and respect per-item targets/max. This also improves staged preview.

Apply:

-              const labelsItem = result.items.find(item => item.type === "add_labels");
-              if (!labelsItem) {
+              const labelItems = result.items.filter(item => item.type === "add_labels");
+              if (labelItems.length === 0) {
                 core.warning("No add-labels item found in agent output");
                 return;
               }
-              core.info(`Found add-labels item with ${labelsItem.labels.length} labels`);
+              core.info(`Found ${labelItems.length} add-labels item(s)`);
               if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
                 await generateStagedPreview({
                   title: "Add Labels",
                   description: "The following labels would be added if staged mode was disabled:",
-                  items: [labelsItem],
-                  renderItem: item => {
+                  items: labelItems,
+                  renderItem: (item) => {
                     let content = "";
                     if (item.item_number) {
                       content += `**Target Issue:** #${item.item_number}\n\n`;
                     } else {
                       content += `**Target:** Current issue/PR\n\n`;
                     }
-                    if (item.labels && item.labels.length > 0) {
+                    if (item.labels?.length > 0) {
                       content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
                     }
                     return content;
                   },
                 });
                 return;
               }
@@
-              let itemNumber;
-              let contextType;
-              if (labelsTarget === "*") {
-                if (labelsItem.item_number) {
-                  itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
-                  if (isNaN(itemNumber) || itemNumber <= 0) {
-                    core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`);
-                    return;
-                  }
-                  contextType = "issue";
-                } else {
-                  core.setFailed('Target is "*" but no item_number specified in labels item');
-                  return;
-                }
-              } else if (labelsTarget && labelsTarget !== "triggering") {
-                itemNumber = parseInt(labelsTarget, 10);
-                if (isNaN(itemNumber) || itemNumber <= 0) {
-                  core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`);
-                  return;
-                }
-                contextType = "issue";
-              } else {
-                if (isIssueContext) {
-                  if (context.payload.issue) {
-                    itemNumber = context.payload.issue.number;
-                    contextType = "issue";
-                  } else {
-                    core.setFailed("Issue context detected but no issue found in payload");
-                    return;
-                  }
-                } else if (isPRContext) {
-                  if (context.payload.pull_request) {
-                    itemNumber = context.payload.pull_request.number;
-                    contextType = "pull request";
-                  } else {
-                    core.setFailed("Pull request context detected but no pull request found in payload");
-                    return;
-                  }
-                }
-              }
-              if (!itemNumber) {
-                core.setFailed("Could not determine issue or pull request number");
-                return;
-              }
-              const requestedLabels = labelsItem.labels || [];
-              core.info(`Requested labels: ${JSON.stringify(requestedLabels)}`);
-              for (const label of requestedLabels) {
-                if (label && typeof label === "string" && label.startsWith("-")) {
-                  core.setFailed(`Label removal is not permitted. Found line starting with '-': ${label}`);
-                  return;
-                }
-              }
-              let validLabels;
-              if (allowedLabels) {
-                validLabels = requestedLabels.filter(label => allowedLabels.includes(label));
-              } else {
-                validLabels = requestedLabels;
-              }
-              let uniqueLabels = validLabels
-                .filter(label => label != null && label !== false && label !== 0)
-                .map(label => String(label).trim())
-                .filter(label => label)
-                .map(label => sanitizeLabelContent(label))
-                .filter(label => label)
-                .map(label => (label.length > 64 ? label.substring(0, 64) : label))
-                .filter((label, index, arr) => arr.indexOf(label) === index);
-              if (uniqueLabels.length > maxCount) {
-                core.info(`too many labels, keep ${maxCount}`);
-                uniqueLabels = uniqueLabels.slice(0, maxCount);
-              }
-              if (uniqueLabels.length === 0) {
-                core.info("No labels to add");
-                core.setOutput("labels_added", "");
-                await core.summary
-                  .addRaw(
-                    `
-            ## Label Addition
-            No labels were added (no valid labels found in agent output).
-            `
-                  )
-                  .write();
-                return;
-              }
-              core.info(`Adding ${uniqueLabels.length} labels to ${contextType} #${itemNumber}: ${JSON.stringify(uniqueLabels)}`);
-              try {
-                await github.rest.issues.addLabels({
-                  owner: context.repo.owner,
-                  repo: context.repo.repo,
-                  issue_number: itemNumber,
-                  labels: uniqueLabels,
-                });
-                core.info(`Successfully added ${uniqueLabels.length} labels to ${contextType} #${itemNumber}`);
-                core.setOutput("labels_added", uniqueLabels.join("\n"));
-                const labelsListMarkdown = uniqueLabels.map(label => `- \`${label}\``).join("\n");
-                await core.summary
-                  .addRaw(
-                    `
-            ## Label Addition
-            Successfully added ${uniqueLabels.length} label(s) to ${contextType} #${itemNumber}:
-            ${labelsListMarkdown}
-            `
-                  )
-                  .write();
-              } catch (error) {
-                const errorMessage = error instanceof Error ? error.message : String(error);
-                core.error(`Failed to add labels: ${errorMessage}`);
-                core.setFailed(`Failed to add labels: ${errorMessage}`);
-              }
+              let anyAdded = false;
+              for (const labelsItem of labelItems) {
+                let itemNumber;
+                let contextType;
+                if (labelsTarget === "*") {
+                  if (labelsItem.item_number) {
+                    itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
+                    if (isNaN(itemNumber) || itemNumber <= 0) {
+                      core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`);
+                      continue;
+                    }
+                    contextType = "issue";
+                  } else {
+                    core.setFailed('Target is "*" but no item_number specified in labels item');
+                    continue;
+                  }
+                } else if (labelsTarget && labelsTarget !== "triggering") {
+                  itemNumber = parseInt(labelsTarget, 10);
+                  if (isNaN(itemNumber) || itemNumber <= 0) {
+                    core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`);
+                    continue;
+                  }
+                  contextType = "issue";
+                } else {
+                  if (isIssueContext && context.payload.issue) {
+                    itemNumber = context.payload.issue.number;
+                    contextType = "issue";
+                  } else if (isPRContext && context.payload.pull_request) {
+                    itemNumber = context.payload.pull_request.number;
+                    contextType = "pull request";
+                  } else {
+                    core.setFailed("Could not determine issue or pull request number");
+                    continue;
+                  }
+                }
+                const requestedLabels = labelsItem.labels || [];
+                core.info(`Requested labels for #${itemNumber}: ${JSON.stringify(requestedLabels)}`);
+                for (const label of requestedLabels) {
+                  if (label && typeof label === "string" && label.startsWith("-")) {
+                    core.setFailed(`Label removal is not permitted. Found line starting with '-': ${label}`);
+                    continue;
+                  }
+                }
+                const validLabels = allowedLabels ? requestedLabels.filter(l => allowedLabels.includes(l)) : requestedLabels;
+                let uniqueLabels = validLabels
+                  .filter(l => l != null && l !== false && l !== 0)
+                  .map(l => String(l).trim())
+                  .filter(Boolean)
+                  .map(sanitizeLabelContent)
+                  .filter(Boolean)
+                  .map(l => (l.length > 64 ? l.substring(0, 64) : l))
+                  .filter((l, i, arr) => arr.indexOf(l) === i);
+                if (uniqueLabels.length > maxCount) {
+                  core.info(`Too many labels for #${itemNumber}, keeping first ${maxCount}`);
+                  uniqueLabels = uniqueLabels.slice(0, maxCount);
+                }
+                if (uniqueLabels.length === 0) {
+                  core.info(`No valid labels to add for #${itemNumber}`);
+                  continue;
+                }
+                try {
+                  await github.rest.issues.addLabels({
+                    owner: context.repo.owner,
+                    repo: context.repo.repo,
+                    issue_number: itemNumber,
+                    labels: uniqueLabels,
+                  });
+                  anyAdded = true;
+                  core.info(`Added ${uniqueLabels.length} labels to ${contextType} #${itemNumber}`);
+                  const labelsListMarkdown = uniqueLabels.map(label => `- \`${label}\``).join("\n");
+                  await core.summary.addRaw(`\n## Label Addition\nAdded ${uniqueLabels.length} label(s) to ${contextType} #${itemNumber}:\n${labelsListMarkdown}\n`).write();
+                } catch (error) {
+                  const errorMessage = error instanceof Error ? error.message : String(error);
+                  core.error(`Failed to add labels for #${itemNumber}: ${errorMessage}`);
+                  core.setFailed(`Failed to add labels for #${itemNumber}: ${errorMessage}`);
+                }
+              }
+              core.setOutput("labels_added", anyAdded ? "true" : "");
🧹 Nitpick comments (2)
.github/workflows/issue-triage.md (2)

110-110: Minor wording nit: “GitHub‑flavored Markdown”.

Prefer proper noun: “GitHub‑flavored Markdown” (or just “Markdown”).

-   - Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top.
+   - Use collapsed‑by‑default sections in GitHub‑flavored Markdown to keep the comment tidy. Collapse all sections except the short main summary at the top.

102-104: Optional: fix nested list indentation (MD007).

Adjust indentation of nested bullets under the “related issues” section.

-   - **If duplicate or related issues were found**, add sections listing them with links:
-     - "### 🔗 Potentially Related Issues (this repo)" – bullet list of same-repo issues with titles and links
-     - If applicable: "### 🌐 Cross-repo related issues (org: appwrite)" – bullet list including `owner/repo#number` with titles and links
+ - **If duplicate or related issues were found**, add sections listing them with links:
+   - "### 🔗 Potentially Related Issues (this repo)" – bullet list of same‑repo issues with titles and links
+   - If applicable: "### 🌐 Cross‑repo related issues (org: appwrite)" – bullet list including `owner/repo#number` with titles and links

Also applies to: 105-110

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1e6572 and 09933ce.

📒 Files selected for processing (2)
  • .github/workflows/issue-triage.lock.yml (43 hunks)
  • .github/workflows/issue-triage.md (3 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/issue-triage.lock.yml

75-75: label "ubuntu-slim" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

🪛 LanguageTool
.github/workflows/issue-triage.md

[uncategorized] ~110-~110: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...apsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all ...

(MARKDOWN_NNP)

🪛 markdownlint-cli2 (0.18.1)
.github/workflows/issue-triage.md

102-102: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


103-103: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


104-104: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


105-105: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


106-106: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


107-107: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


108-108: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


109-109: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


110-110: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Realtime)
  • GitHub Check: E2E Service Test (Health)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Databases/TablesDB)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: Unit Test
  • GitHub Check: E2E General Test
  • GitHub Check: Benchmark
  • GitHub Check: agent
  • GitHub Check: scan
🔇 Additional comments (3)
.github/workflows/issue-triage.lock.yml (2)

541-672: LGTM: add_comment batching with target "*" is correctly implemented.

Filtering all add_comment items and iterating with GH_AW_COMMENT_TARGET="*" enables true batch comments. Matches PR goal.


1272-1273: Good: safe-outputs config enables batch comments.

add_comment has max: 10 and target: "*", allowing multiple comments per run. This complements the job logic.

.github/workflows/issue-triage.md (1)

24-31: LGTM: safe-outputs now supports batch mode.

add-labels: { max: 100, target: "*" } and add-comment: { max: 10, target: "*" } align with batch processing requirements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
.github/workflows/issue-triage.lock.yml (1)

1005-1061: Process all add_labels items, not just the first.

Currently uses find(...); only one labels item is applied, defeating batch mode across issues.

- const labelsItem = result.items.find(item => item.type === "add_labels");
- if (!labelsItem) {
+ const labelItems = result.items.filter(item => item.type === "add_labels");
+ if (labelItems.length === 0) {
   core.warning("No add-labels item found in agent output");
   return;
 }
- core.info(`Found add-labels item with ${labelsItem.labels.length} labels`);
+ core.info(`Found ${labelItems.length} add-labels item(s)`);

- if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
-   await generateStagedPreview({
-     title: "Add Labels",
-     description: "The following labels would be added if staged mode was disabled:",
-     items: [labelsItem],
-     renderItem: item => {
-       let content = "";
-       if (item.item_number) {
-         content += `**Target Issue:** #${item.item_number}\n\n`;
-       } else {
-         content += `**Target:** Current issue/PR\n\n`;
-       }
-       if (item.labels && item.labels.length > 0) {
-         content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
-       }
-       return content;
-     },
-   });
-   return;
- }
+ if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
+   await generateStagedPreview({
+     title: "Add Labels",
+     description: "The following labels would be added if staged mode was disabled:",
+     items: labelItems,
+     renderItem: item => {
+       let content = "";
+       if (item.item_number) content += `**Target Issue:** #${item.item_number}\n\n`;
+       else content += `**Target:** Current issue/PR\n\n`;
+       if (item.labels?.length) content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
+       return content;
+     },
+   });
+   return;
+ }
 
- const labelsTarget = process.env.GH_AW_LABELS_TARGET || "triggering";
+ const labelsTarget = process.env.GH_AW_LABELS_TARGET || "triggering";
  core.info(`Labels target configuration: ${labelsTarget}`);
 
- let itemNumber;
- let contextType;
- if (labelsTarget === "*") {
-   if (labelsItem.item_number) {
-     itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
-     if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`); return; }
-     contextType = "issue";
-   } else {
-     core.setFailed('Target is "*" but no item_number specified in labels item');
-     return;
-   }
- } else if (labelsTarget && labelsTarget !== "triggering") {
-   itemNumber = parseInt(labelsTarget, 10);
-   if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`); return; }
-   contextType = "issue";
- } else {
-   if (isIssueContext) {
-     if (context.payload.issue) { itemNumber = context.payload.issue.number; contextType = "issue"; }
-     else { core.setFailed("Issue context detected but no issue found in payload"); return; }
-   } else if (isPRContext) {
-     if (context.payload.pull_request) { itemNumber = context.payload.pull_request.number; contextType = "pull request"; }
-     else { core.setFailed("Pull request context detected but no pull request found in payload"); return; }
-   }
- }
- if (!itemNumber) {
-   core.setFailed("Could not determine issue or pull request number");
-   return;
- }
- const requestedLabels = labelsItem.labels || [];
- ...
- await github.rest.issues.addLabels({ issue_number: itemNumber, labels: uniqueLabels })
+ for (const labelsItem of labelItems) {
+   let itemNumber;
+   let contextType;
+   if (labelsTarget === "*") {
+     if (labelsItem.item_number) {
+       itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
+       if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`); continue; }
+       contextType = "issue";
+     } else {
+       core.setFailed('Target is "*" but no item_number specified in labels item');
+       continue;
+     }
+   } else if (labelsTarget && labelsTarget !== "triggering") {
+     itemNumber = parseInt(labelsTarget, 10);
+     if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`); continue; }
+     contextType = "issue";
+   } else {
+     if (isIssueContext && context.payload.issue) { itemNumber = context.payload.issue.number; contextType = "issue"; }
+     else if (isPRContext && context.payload.pull_request) { itemNumber = context.payload.pull_request.number; contextType = "pull request"; }
+     else { core.setFailed("Could not determine issue or pull request number"); continue; }
+   }
+
+   const requestedLabels = labelsItem.labels || [];
+   // ... keep validation and uniqueLabels logic unchanged
+   await github.rest.issues.addLabels({
+     owner: context.repo.owner,
+     repo: context.repo.repo,
+     issue_number: itemNumber,
+     labels: uniqueLabels,
+   });
+ }

Also applies to: 1113-1169

🧹 Nitpick comments (1)
.github/workflows/issue-triage.md (1)

111-114: Minor wording nits (optional).

Capitalize “Markdown” as a proper noun; keeps docs polished.

-   - Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. Ensure text is bolded using markdown syntax.
+   - Use collapsed-by-default sections in the GitHub Markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. Ensure text is bolded using Markdown syntax.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09933ce and 73d8fbf.

📒 Files selected for processing (2)
  • .github/workflows/issue-triage.lock.yml (42 hunks)
  • .github/workflows/issue-triage.md (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/issue-triage.lock.yml

75-75: label "ubuntu-slim" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

🪛 LanguageTool
.github/workflows/issue-triage.md

[uncategorized] ~112-~112: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...apsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all ...

(MARKDOWN_NNP)


[uncategorized] ~112-~112: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...at the top. Ensure text is bolded using markdown syntax. - Do not indicate/encourage ...

(MARKDOWN_NNP)

🪛 markdownlint-cli2 (0.18.1)
.github/workflows/issue-triage.md

97-97: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


98-98: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


99-99: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


102-102: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


103-103: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


104-104: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


105-105: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


106-106: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


107-107: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


108-108: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


109-109: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


110-110: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


111-111: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


113-113: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: Setup & Build Appwrite Image
  • GitHub Check: scan
🔇 Additional comments (5)
.github/workflows/issue-triage.md (3)

24-30: Batch mode enabled for comments and labels — good change.

Explicit max with target:"*" for both add-labels and add-comment enables multi-issue runs as intended.


35-38: Labels toolset exposure looks correct.

Including the github “labels” toolset aligns with later label operations.


11-21: Stricter error pattern set — looks fine.

Good guardrails to avoid false “error” triggers from issue text.

.github/workflows/issue-triage.lock.yml (2)

1268-1273: Batch comments correctly enabled in lock.

Safe-outputs config sets add_comment max:10 and GH_AW_COMMENT_TARGET:"*". This unblocks multi-issue comments.

Optionally bump max if you expect >10 issues per run.

Also applies to: 540-542


499-510: The review comment is factually incorrect about runner availability.

ubuntu-slim is a valid GitHub-hosted runner label (single-CPU container-based runner, public preview). The code correctly uses this available runner option. No changes are required.

Likely an incorrect or invalid review comment.

Comment on lines +53 to +54
3. Use the `get_comments` tool to retrieve all the comments on the issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use the correct tool name: get_issue_comments, not get_comments.

The GitHub MCP exposes get_issue_comments; get_comments may not exist and can cause tool failures.

-3. Use the `get_comments` tool to retrieve all the comments on the issue.
+3. Use the `get_issue_comments` tool to retrieve all the comments on the issue.

After editing, run: gh aw compile

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
3. Use the `get_comments` tool to retrieve all the comments on the issue.
3. Use the `get_issue_comments` tool to retrieve all the comments on the issue.
🤖 Prompt for AI Agents
In .github/workflows/issue-triage.md around lines 53 to 54, the workflow step
references the wrong tool name `get_comments`; update the text to use the
correct GitHub MCP tool name `get_issue_comments` wherever `get_comments`
appears in that line, then save the file and run `gh aw compile` as instructed
to validate the change.

Comment on lines +95 to +101
10. Apply the selected labels:

- Use the `update_issue` tool to apply the labels to the issue
- DO NOT communicate directly with users
- If no labels are clearly applicable, do not apply any labels

10. Add an issue comment to the issue with your analysis:
11. Add an issue comment to the issue with your analysis:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix labeling step — use add_labels (not update_issue) to apply labels.

As written, the agent will not emit add_labels items, breaking batch labeling.

-10. Apply the selected labels:
-
-   - Use the `update_issue` tool to apply the labels to the issue
+10. Apply the selected labels:
+
+   - Use the `add_labels` tool to apply the labels to the issue

After editing, run: gh aw compile

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
10. Apply the selected labels:
- Use the `update_issue` tool to apply the labels to the issue
- DO NOT communicate directly with users
- If no labels are clearly applicable, do not apply any labels
10. Add an issue comment to the issue with your analysis:
11. Add an issue comment to the issue with your analysis:
10. Apply the selected labels:
- Use the `add_labels` tool to apply the labels to the issue
- DO NOT communicate directly with users
- If no labels are clearly applicable, do not apply any labels
11. Add an issue comment to the issue with your analysis:
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

97-97: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


98-98: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


99-99: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)

🤖 Prompt for AI Agents
.github/workflows/issue-triage.md around lines 95 to 101: the workflow step
instructs the agent to "Use the `update_issue` tool to apply the labels", but
batch labeling expects `add_labels` items; change the instruction to call or
emit `add_labels` (not `update_issue`) when applying labels. Update the text to
explicitly instruct using the `add_labels` tool/command and ensure any examples
or templates emit the correct `add_labels` payload so the batch labeling handler
receives label additions; after editing, run `gh aw compile` as noted.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
.github/workflows/issue-triage.md (2)

53-54: Use the correct tool name and avoid duplicate fetch.

Replace get_comments with get_issue_comments; step 6 already fetches comments, so either remove step 3 or reference it as “already retrieved.”

-3. Use the `get_comments` tool to retrieve all the comments on the issue.
+3. Use the `get_issue_comments` tool to retrieve all comments for the issue.

Optionally remove step 3 and keep only step 6 to avoid duplication.

Also applies to: 65-67


95-101: Fix labeling step — use add_labels (not update_issue).

As written, the agent won’t emit add_labels items; batch labeling breaks. Switch to add_labels and recompile.

 10. Apply the selected labels:
-
-   - Use the `update_issue` tool to apply the labels to the issue
+   - Use the `add_labels` tool to apply the labels to the issue
    - DO NOT communicate directly with users
    - If no labels are clearly applicable, do not apply any labels
.github/workflows/issue-triage.lock.yml (1)

1001-1011: Process all add_labels items, not just the first.

Current code uses find(...) and previews a single item; only one label action runs. Iterate over all add_labels items and preview all.

- const labelsItem = result.items.find(item => item.type === "add_labels");
- if (!labelsItem) {
+ const labelItems = result.items.filter(item => item.type === "add_labels");
+ if (labelItems.length === 0) {
   core.warning("No add-labels item found in agent output");
   return;
 }
- core.info(`Found add-labels item with ${labelsItem.labels.length} labels`);
+ core.info(`Found ${labelItems.length} add-labels item(s)`);
 
- if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
-   await generateStagedPreview({
+ if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") {
+   await generateStagedPreview({
      title: "Add Labels",
      description: "The following labels would be added if staged mode was disabled:",
-     items: [labelsItem],
-     renderItem: item => {
+     items: labelItems,
+     renderItem: item => {
        let content = "";
        if (item.item_number) {
          content += `**Target Issue:** #${item.item_number}\n\n`;
        } else {
          content += `**Target:** Current issue/PR\n\n`;
        }
        if (item.labels && item.labels.length > 0) {
          content += `**Labels to add:** ${item.labels.join(", ")}\n\n`;
        }
        return content;
      },
    });
    return;
  }
 
- const labelsTarget = process.env.GH_AW_LABELS_TARGET || "triggering";
+ const labelsTarget = process.env.GH_AW_LABELS_TARGET || "triggering";
  core.info(`Labels target configuration: ${labelsTarget}`);
 
- let itemNumber;
- let contextType;
- if (labelsTarget === "*") {
-   if (labelsItem.item_number) {
-     itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
-     if (isNaN(itemNumber) || itemNumber <= 0) {
-       core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`);
-       return;
-     }
-     contextType = "issue";
-   } else {
-     core.setFailed('Target is "*" but no item_number specified in labels item');
-     return;
-   }
- } else if (labelsTarget && labelsTarget !== "triggering") {
-   itemNumber = parseInt(labelsTarget, 10);
-   if (isNaN(itemNumber) || itemNumber <= 0) {
-     core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`);
-     return;
-   }
-   contextType = "issue";
- } else {
-   if (context.payload.issue) { itemNumber = context.payload.issue.number; contextType = "issue"; }
-   else if (context.payload.pull_request) { itemNumber = context.payload.pull_request.number; contextType = "pull request"; }
-   else { core.setFailed("Could not determine issue or pull request number"); return; }
- }
- if (!itemNumber) { core.setFailed("Could not determine issue or pull request number"); return; }
- const requestedLabels = labelsItem.labels || [];
- ...
- await github.rest.issues.addLabels({ issue_number: itemNumber, labels: uniqueLabels })
+ for (const labelsItem of labelItems) {
+   let itemNumber;
+   let contextType;
+   if (labelsTarget === "*") {
+     if (labelsItem.item_number) {
+       itemNumber = typeof labelsItem.item_number === "number" ? labelsItem.item_number : parseInt(String(labelsItem.item_number), 10);
+       if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid item_number specified: ${labelsItem.item_number}`); continue; }
+       contextType = "issue";
+     } else {
+       core.setFailed('Target is "*" but no item_number specified in labels item');
+       continue;
+     }
+   } else if (labelsTarget && labelsTarget !== "triggering") {
+     itemNumber = parseInt(labelsTarget, 10);
+     if (isNaN(itemNumber) || itemNumber <= 0) { core.setFailed(`Invalid issue number in target configuration: ${labelsTarget}`); continue; }
+     contextType = "issue";
+   } else {
+     if (context.payload.issue) { itemNumber = context.payload.issue.number; contextType = "issue"; }
+     else if (context.payload.pull_request) { itemNumber = context.payload.pull_request.number; contextType = "pull request"; }
+     else { core.setFailed("Could not determine issue or pull request number"); continue; }
+   }
+   const requestedLabels = labelsItem.labels || [];
+   // existing validation/sanitization…
+   await github.rest.issues.addLabels({
+     owner: context.repo.owner,
+     repo: context.repo.repo,
+     issue_number: itemNumber,
+     labels: uniqueLabels,
+   });
+ }

Also applies to: 1012-1030, 1061-1105, 1144-1169

🧹 Nitpick comments (1)
.github/workflows/issue-triage.md (1)

24-30: Enable larger batch comments.

max: 10 may throttle batch triage. Consider raising to 50 to match expected daily volume, then recompile.

 safe-outputs:
   add-labels:
     max: 100
     target: "*"
   add-comment:
-    max: 10
+    max: 50
     target: "*"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73d8fbf and babddf2.

📒 Files selected for processing (2)
  • .github/workflows/issue-triage.lock.yml (42 hunks)
  • .github/workflows/issue-triage.md (2 hunks)
🧰 Additional context used
🪛 actionlint (1.7.8)
.github/workflows/issue-triage.lock.yml

75-75: label "ubuntu-slim" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-11-arm", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-26-xlarge", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file

(runner-label)

🪛 LanguageTool
.github/workflows/issue-triage.md

[uncategorized] ~112-~112: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...apsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all ...

(MARKDOWN_NNP)

🪛 markdownlint-cli2 (0.18.1)
.github/workflows/issue-triage.md

97-97: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


98-98: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


99-99: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


102-102: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


103-103: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


104-104: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


105-105: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


106-106: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


107-107: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


108-108: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


109-109: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


110-110: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


111-111: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


113-113: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: E2E Service Test (Tokens)
  • GitHub Check: E2E Service Test (VCS)
  • GitHub Check: E2E Service Test (Users)
  • GitHub Check: E2E Service Test (Teams)
  • GitHub Check: E2E Service Test (Sites)
  • GitHub Check: E2E Service Test (Projects)
  • GitHub Check: E2E Service Test (Proxy)
  • GitHub Check: E2E Service Test (Databases/Legacy)
  • GitHub Check: E2E Service Test (Account)
  • GitHub Check: E2E Service Test (FunctionsSchedule)
  • GitHub Check: E2E Service Test (GraphQL)
  • GitHub Check: E2E Service Test (Functions)
  • GitHub Check: E2E Service Test (Console)
  • GitHub Check: E2E Service Test (Avatars)
  • GitHub Check: E2E Service Test (Site Screenshots)
  • GitHub Check: E2E Service Test (Dev Keys)
  • GitHub Check: Unit Test
  • GitHub Check: E2E General Test
  • GitHub Check: agent
  • GitHub Check: scan
🔇 Additional comments (4)
.github/workflows/issue-triage.md (1)

11-21: LGTM on stricter error patterning.

Good addition; helps avoid false error triggers from issue text.

.github/workflows/issue-triage.lock.yml (3)

75-81: Runner label may be invalid on GitHub‑hosted runners.

ubuntu-slim isn’t a standard label; switch to ubuntu-latest unless you use a self‑hosted runner with this label.

-    runs-on: ubuntu-slim
+    runs-on: ubuntu-latest

If intentional (self‑hosted), ignore.


1272-1273: Batch comments unblocked — good.

Safe‑outputs config now sets add_comment max:10 and target:"*". This resolves the prior “max: 1” limitation.


62-70: LGTM on GH_AW_ERROR_PATTERNS in lock.

Matches source; good for consistent log parsing.

Comment on lines +111 to 114
- If appropriate break the issue down to sub-tasks and write a checklist of things to do
- Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. For bolded section titles, wrap the text with `<strong>` and `</strong>` to make it bold.
- Do not indicate/encourage a community member to submit a PR for the issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor wording polish.

Capitalize Markdown.

-   - Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy.
+   - Use collapsed-by-default sections in GitHub Markdown to keep the comment tidy.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- If appropriate break the issue down to sub-tasks and write a checklist of things to do
- Use collapsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. For bolded section titles, wrap the text with `<strong>` and `</strong>` to make it bold.
- Do not indicate/encourage a community member to submit a PR for the issue.
- If appropriate break the issue down to sub-tasks and write a checklist of things to do
- Use collapsed-by-default sections in GitHub Markdown to keep the comment tidy. Collapse all sections except the short main summary at the top. For bolded section titles, wrap the text with `<strong>` and `</strong>` to make it bold.
- Do not indicate/encourage a community member to submit a PR for the issue.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~112-~112: Did you mean the formatting language “Markdown” (= proper noun)?
Context: ...apsed-by-default sections in the GitHub markdown to keep the comment tidy. Collapse all ...

(MARKDOWN_NNP)

🪛 markdownlint-cli2 (0.18.1)

111-111: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


112-112: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)


113-113: Unordered list indentation
Expected: 0; Actual: 3

(MD007, ul-indent)

🤖 Prompt for AI Agents
.github/workflows/issue-triage.md around lines 111 to 114: change the lowercase
"markdown" to the proper capitalized form "Markdown" (ideally "GitHub Markdown")
in the second bullet so the sentence reads with correct capitalization.

@stnguyen90 stnguyen90 merged commit b793a11 into main Nov 13, 2025
51 checks passed
@stnguyen90 stnguyen90 deleted the fix/issue-triage-batch-mode branch November 13, 2025 01:28
@stnguyen90 stnguyen90 mentioned this pull request Dec 10, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants