From 69231a47caad2859655bcb236cd28628ed9a483d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:06:32 +0000 Subject: [PATCH 1/7] Initial plan From a7a94a0c22b8b5d427fc17990b54f41c41ce6738 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:14:58 +0000 Subject: [PATCH 2/7] Add comprehensive rate limiting controls documentation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../docs/reference/rate-limiting-controls.md | 480 ++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 docs/src/content/docs/reference/rate-limiting-controls.md diff --git a/docs/src/content/docs/reference/rate-limiting-controls.md b/docs/src/content/docs/reference/rate-limiting-controls.md new file mode 100644 index 0000000000..ad6bee9d70 --- /dev/null +++ b/docs/src/content/docs/reference/rate-limiting-controls.md @@ -0,0 +1,480 @@ +--- +title: Rate Limiting Controls +description: Built-in protections and controls to prevent runaway agentic workflows and snowballing effects in GitHub Agentic Workflows. +sidebar: + order: 1450 +--- + +GitHub Agentic Workflows includes multiple layers of protection to prevent runaway workflows and exponential growth patterns. These controls work together to ensure safe, predictable execution even with autonomous agents. + +## Overview of Protection Layers + +The system employs defense-in-depth with multiple independent controls: + +1. **Bot non-triggering** - Prevents cascading workflow chains +2. **Concurrency controls** - Serializes execution to prevent parallel explosions +3. **Timeouts** - Hard limits on execution time +4. **Rate limiting** - Throttles workflow trigger frequency per user +5. **Read-only agents** - Prevents direct write access +6. **Safe output limits** - Caps automated operations +7. **Built-in delays** - Rate-limits high-risk operations +8. **Manual review gates** - Optional human oversight for critical actions + +## Bot Non-Triggering Behavior + +The GitHub Actions bot account (`github-actions[bot]`) does **not trigger workflow events** when creating or modifying issues, pull requests, or comments. This prevents cascading chains where one workflow triggers another indefinitely. + +**How it works:** + +```yaml wrap +on: + issues: + types: [opened, edited] + issue_comment: + types: [created] +``` + +When a workflow with these triggers creates an issue or posts a comment via safe outputs, those actions do **not** trigger new workflow runs. This breaks potential infinite loops at the source. + +**Example scenario prevented:** +1. Workflow A creates an issue via `create-issue` +2. Issue creation does **not** trigger Workflow B (even with `on: issues`) +3. Chain stops automatically + +> [!NOTE] +> This is a built-in GitHub Actions behavior, not specific to gh-aw. The bot account is explicitly excluded from triggering workflows to prevent automation loops. + +## Concurrency Groups + +Workflows use **two levels of concurrency control** to prevent parallel execution explosions: + +### Per-Workflow Concurrency + +Each workflow execution is placed in a concurrency group based on its context: + +```yaml wrap +concurrency: + group: gh-aw-${{ github.workflow }}-${{ issue.number }} + cancel-in-progress: false +``` + +**Benefits:** +- Prevents multiple simultaneous runs for the same issue/PR +- Queues work sequentially instead of running in parallel +- Avoids race conditions and duplicate operations + +### Per-Engine Concurrency + +Agent jobs use a second concurrency group based on the AI engine: + +```yaml wrap +jobs: + agent: + concurrency: + group: gh-aw-copilot + cancel-in-progress: false +``` + +**Benefits:** +- Only one agent job runs at a time per engine +- Prevents AI resource exhaustion +- Ensures predictable token usage +- Avoids overwhelming external AI services + +> [!TIP] +> See [Concurrency Control](/gh-aw/reference/concurrency/) for detailed configuration options and customization. + +## Job Timeouts + +Every job has a **maximum execution time** to prevent indefinite running: + +### Workflow-Level Timeout + +Default timeout for all jobs: + +```yaml wrap +jobs: + agent: + timeout-minutes: 360 # 6 hours default +``` + +### Agent Job Timeout + +The agent job (where AI reasoning occurs) has a configurable timeout: + +```yaml wrap +--- +engine: + id: copilot + timeout: 60 # Minutes (default: 360) +--- +``` + +**Protection provided:** +- Agent cannot run indefinitely even if stuck +- Automatic cancellation after timeout +- Prevents cost overruns from hung processes +- Resource cleanup guaranteed + +### Stop-After Field + +Additional control for workflow runtime limits: + +```yaml wrap +--- +stop-after: +48h # Stop workflow after 48 hours +--- +``` + +**How it works:** +- Evaluated in the agent job's `if:` condition +- Compares current time against workflow start time +- Automatically skips execution if time limit exceeded +- Minimum unit is hours (`+1h`, `+24h`, `+48h`) + +**Example:** + +```yaml wrap +--- +name: Long-Running Analysis +on: + schedule: + - cron: '0 0 * * *' # Daily +stop-after: +6h +--- + +Analysis workflow that automatically stops if not +completed within 6 hours of the scheduled trigger time. +``` + +> [!NOTE] +> The `stop-after` field is checked in the generated workflow action and prevents execution if exceeded, ensuring workflows don't continue beyond their intended window. + +## Read-Only Agent Tokens + +Agents run with **read-only GitHub tokens** by default. They cannot directly: +- Create or modify issues +- Update pull requests +- Post comments +- Change repository settings +- Trigger other workflows + +**Token scope:** + +```yaml wrap +permissions: + contents: read # Read code only + issues: read # Read issues only + pull-requests: read # Read PRs only +``` + +All write operations must go through the **safe outputs system**, which provides validation, auditing, and rate limiting. + +## Safe Outputs Rate Limiting + +The [safe outputs system](/gh-aw/reference/safe-outputs/) provides write capabilities with built-in limits. High-risk operations have **default maximums** to prevent exponential growth: + +### Default Maximum Limits + +| Operation | Default Max | Purpose | +|-----------|-------------|---------| +| `assign-to-agent` | **1** | Prevent agent spawn cascades | +| `assign-to-bot` | **1** | Prevent bot assignment loops | +| `dispatch-workflow` | **1** | Prevent workflow trigger explosions | +| `create-issue` | **1** | Limit automated issue creation | +| `create-pull-request` | **1** | Limit automated PR creation | + +**Example configuration:** + +```yaml wrap +safe-outputs: + assign-to-agent: + # Default max: 1 (can be increased if needed) + max: 3 # Allow up to 3 agent assignments + + dispatch-workflow: + # Default max: 1 (prevents cascading triggers) + max: 2 # Allow triggering 2 workflows +``` + +### Why These Limits Matter + +**Without limits:** +```mermaid +graph TD + W1[Workflow 1] -->|assigns agent| I1[Issue 1] + W1 -->|assigns agent| I2[Issue 2] + W1 -->|assigns agent| I3[Issue 3] + I1 -->|triggers| W2[Workflow 2] + I2 -->|triggers| W3[Workflow 3] + I3 -->|triggers| W4[Workflow 4] + W2 -->|assigns 3 more| MORE1[...] + W3 -->|assigns 3 more| MORE2[...] + W4 -->|assigns 3 more| MORE3[...] +``` + +**With default max: 1:** +```mermaid +graph TD + W1[Workflow 1] -->|assigns 1 agent| I1[Issue 1] + I1 -->|triggers| W2[Workflow 2] + W2 -->|assigns 1 agent| I2[Issue 2] + style W1 fill:#e1f5e1 + style W2 fill:#e1f5e1 +``` + +Linear growth instead of exponential explosion. + +## Built-In Delays + +Critical operations include **mandatory delays** to prevent burst patterns: + +### Agent Assignment Delay + +When assigning agents to multiple issues, a **10-second delay** occurs between assignments: + +```javascript +// From assign_copilot_to_created_issues.cjs +if (i < issueEntries.length - 1) { + core.info("Waiting 10 seconds before processing next agent assignment..."); + await sleep(10000); +} +``` + +**Protection:** +- Prevents spawning many agents simultaneously +- Gives each agent time to start before next assignment +- Reduces API burst load +- Allows monitoring and cancellation if needed + +### Workflow Dispatch Delay + +Workflow dispatches have a **5-second delay** between triggers: + +```javascript +// From dispatch_workflow.cjs +if (lastDispatchTime > 0) { + const timeSinceLastDispatch = Date.now() - lastDispatchTime; + const delayNeeded = 5000 - timeSinceLastDispatch; + if (delayNeeded > 0) { + core.info(`Waiting ${Math.ceil(delayNeeded / 1000)} seconds before next dispatch...`); + await new Promise(resolve => setTimeout(resolve, delayNeeded)); + } +} +``` + +**Protection:** +- Prevents rapid-fire workflow triggering +- Spreads load over time +- Allows cancellation window +- Reduces GitHub API pressure + +> [!IMPORTANT] +> These delays are **hardcoded** in the safe outputs implementation and cannot be disabled. They are essential safety features. + +## Manual Review with GitHub Environments + +For sensitive operations, you can require **manual approval** before execution using GitHub Environments: + +```yaml wrap +safe-outputs: + dispatch-workflow: + environment: production # Requires approval + max: 3 +``` + +**Configuration steps:** + +1. Create an environment in your repository (Settings → Environments) +2. Add required reviewers +3. Reference the environment in safe output configuration + +**Approval flow:** + +```mermaid +sequenceDiagram + participant Agent + participant SafeOutput + participant Reviewer + participant Action + + Agent->>SafeOutput: Request dispatch-workflow + SafeOutput->>Reviewer: ⏸️ Waiting for approval + Reviewer->>SafeOutput: ✅ Approve + SafeOutput->>Action: Execute workflow dispatch +``` + +**Benefits:** +- Human oversight for critical operations +- Audit trail of approvals +- Ability to reject risky actions +- Compliance with change management policies + +> [!TIP] +> Use environments for operations like: +> - Production workflow dispatches +> - Cross-repository operations +> - Bulk issue/PR creation +> - Security-sensitive actions + +## Rate Limiting Per User + +The `rate-limit:` configuration (see [RATE_LIMITING.md](https://github.com/github/gh-aw/blob/main/docs/RATE_LIMITING.md)) prevents individual users from triggering workflows too frequently: + +```yaml wrap +--- +rate-limit: + max: 5 # Maximum runs per window + window: 60 # Time window in minutes +--- +``` + +**How it works:** +1. Pre-activation job checks recent workflow runs +2. Counts runs by the same user within time window +3. Cancels current run if limit exceeded +4. Prevents both accidental and intentional abuse + +**Example protection:** + +```yaml wrap +--- +name: Expensive Analysis +on: + issue_comment: + types: [created] +rate-limit: + max: 3 + window: 60 +--- +``` + +User cannot trigger more than 3 analysis runs per hour, even by posting multiple comments. + +## Combined Protection Example + +Here's how multiple layers work together: + +```yaml wrap +--- +name: Safe Agent Workflow +engine: + id: copilot + timeout: 60 # 1 hour max + concurrency: + group: gh-aw-copilot # One at a time +on: + issues: + types: [opened] +rate-limit: + max: 5 # 5 per hour per user + window: 60 +stop-after: +2h # Stop after 2 hours +safe-outputs: + assign-to-agent: + max: 1 # Only 1 agent assignment + environment: production # Requires approval +--- + +This workflow has multiple safety layers: +- Rate limited per user +- Concurrency controlled +- Time limited +- Manual approval required +- Single agent assignment only +``` + +**Protection layers:** +1. ✅ User can trigger max 5 times/hour (rate-limit) +2. ✅ Only 1 workflow runs at a time (concurrency) +3. ✅ Workflow stops after 2 hours (stop-after) +4. ✅ Agent job limited to 60 minutes (timeout) +5. ✅ Manual approval needed for agent assignment (environment) +6. ✅ Max 1 agent assigned (safe output limit) +7. ✅ 10-second delay before assignment (built-in) +8. ✅ Agent creation won't trigger new workflows (bot non-triggering) + +## Best Practices + +### Start Conservative + +Begin with strict limits and relax as needed: + +```yaml wrap +# Initial configuration - very safe +safe-outputs: + assign-to-agent: + max: 1 # Start with 1 + dispatch-workflow: + max: 1 # Start with 1 + +rate-limit: + max: 3 # Low frequency + window: 60 +``` + +Monitor behavior, then increase limits if justified. + +### Use Environments for High-Risk Operations + +Require manual approval for operations that: +- Trigger other workflows +- Create many resources +- Cross repository boundaries +- Affect production systems + +### Monitor and Audit + +Regularly review: +- Workflow run history +- Safe output execution logs +- Rate limit cancellations +- Timeout occurrences + +Look for patterns indicating configuration adjustments needed. + +### Layer Controls + +Don't rely on a single protection mechanism. Use multiple: +- Rate limiting **AND** concurrency control +- Timeouts **AND** stop-after +- Safe output limits **AND** environments + +Defense-in-depth ensures reliability. + +## Troubleshooting + +### Workflows Not Running + +**Symptom:** Workflow run immediately cancelled + +**Check:** +1. Rate limit exceeded? Look for "rate limit" in pre-activation logs +2. Concurrency queue full? Check other running workflows +3. Stop-after time exceeded? Verify workflow start time + +### Agent Assignments Slow + +**Symptom:** Multiple agent assignments take longer than expected + +**Explanation:** Built-in 10-second delays are working as designed. If assigning 5 agents, expect ~40 seconds total (4 delays). + +**This is intentional** to prevent overwhelming the system. + +### Workflow Dispatch Not Triggering + +**Symptom:** dispatch-workflow safe output runs but target workflow doesn't start + +**Check:** +1. Max dispatch limit (default: 1) - only first dispatch succeeds +2. 5-second delay between dispatches +3. Target workflow `on: workflow_dispatch` configuration +4. Environment approval still pending + +## Related Documentation + +- [Safe Outputs](/gh-aw/reference/safe-outputs/) - Write operations with validation +- [Concurrency Control](/gh-aw/reference/concurrency/) - Execution serialization +- [Frontmatter Reference](/gh-aw/reference/frontmatter/) - Complete configuration options +- [Permissions](/gh-aw/reference/permissions/) - Token scopes and access control +- [GitHub Actions Security](https://docs.github.com/en/actions/security-guides) - GitHub's security guidance From 8a0065cac5e972dbdaee2e5107d7eb067cf4653f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:29:42 +0000 Subject: [PATCH 3/7] Fix concurrency group pattern in rate-limiting-controls.md Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- docs/src/content/docs/reference/rate-limiting-controls.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/reference/rate-limiting-controls.md b/docs/src/content/docs/reference/rate-limiting-controls.md index ad6bee9d70..6abfe9323a 100644 --- a/docs/src/content/docs/reference/rate-limiting-controls.md +++ b/docs/src/content/docs/reference/rate-limiting-controls.md @@ -54,12 +54,14 @@ Each workflow execution is placed in a concurrency group based on its context: ```yaml wrap concurrency: - group: gh-aw-${{ github.workflow }}-${{ issue.number }} + group: gh-aw-${{ github.workflow }} cancel-in-progress: false ``` +The actual concurrency group pattern varies based on trigger type (includes issue numbers, PR numbers, or branch refs). See [Concurrency Control](/gh-aw/reference/concurrency/) for specific patterns. + **Benefits:** -- Prevents multiple simultaneous runs for the same issue/PR +- Prevents multiple simultaneous runs for the same context - Queues work sequentially instead of running in parallel - Avoids race conditions and duplicate operations From cb4de4539f0ee63a6cffdabe774c2e6c80ec3887 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:38:14 +0000 Subject: [PATCH 4/7] Apply unbloat-docs guidelines to rate-limiting-controls.md Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../docs/reference/rate-limiting-controls.md | 413 +++--------------- 1 file changed, 49 insertions(+), 364 deletions(-) diff --git a/docs/src/content/docs/reference/rate-limiting-controls.md b/docs/src/content/docs/reference/rate-limiting-controls.md index 6abfe9323a..5963212999 100644 --- a/docs/src/content/docs/reference/rate-limiting-controls.md +++ b/docs/src/content/docs/reference/rate-limiting-controls.md @@ -1,477 +1,162 @@ --- title: Rate Limiting Controls -description: Built-in protections and controls to prevent runaway agentic workflows and snowballing effects in GitHub Agentic Workflows. +description: Built-in protections to prevent runaway agentic workflows and exponential growth. sidebar: order: 1450 --- -GitHub Agentic Workflows includes multiple layers of protection to prevent runaway workflows and exponential growth patterns. These controls work together to ensure safe, predictable execution even with autonomous agents. +GitHub Agentic Workflows uses defense-in-depth to prevent runaway workflows: bot non-triggering, concurrency controls, timeouts, rate limiting, read-only agents, safe output limits, built-in delays, and manual review gates. -## Overview of Protection Layers +## Bot Non-Triggering -The system employs defense-in-depth with multiple independent controls: - -1. **Bot non-triggering** - Prevents cascading workflow chains -2. **Concurrency controls** - Serializes execution to prevent parallel explosions -3. **Timeouts** - Hard limits on execution time -4. **Rate limiting** - Throttles workflow trigger frequency per user -5. **Read-only agents** - Prevents direct write access -6. **Safe output limits** - Caps automated operations -7. **Built-in delays** - Rate-limits high-risk operations -8. **Manual review gates** - Optional human oversight for critical actions - -## Bot Non-Triggering Behavior - -The GitHub Actions bot account (`github-actions[bot]`) does **not trigger workflow events** when creating or modifying issues, pull requests, or comments. This prevents cascading chains where one workflow triggers another indefinitely. - -**How it works:** +The `github-actions[bot]` account does not trigger workflow events. When a workflow creates an issue or posts a comment via safe outputs, it won't trigger other workflows - preventing infinite loops. ```yaml wrap on: issues: - types: [opened, edited] - issue_comment: - types: [created] + types: [opened] ``` -When a workflow with these triggers creates an issue or posts a comment via safe outputs, those actions do **not** trigger new workflow runs. This breaks potential infinite loops at the source. - -**Example scenario prevented:** -1. Workflow A creates an issue via `create-issue` -2. Issue creation does **not** trigger Workflow B (even with `on: issues`) -3. Chain stops automatically - -> [!NOTE] -> This is a built-in GitHub Actions behavior, not specific to gh-aw. The bot account is explicitly excluded from triggering workflows to prevent automation loops. +This workflow won't be triggered by issues created by safe outputs. ## Concurrency Groups -Workflows use **two levels of concurrency control** to prevent parallel execution explosions: - -### Per-Workflow Concurrency - -Each workflow execution is placed in a concurrency group based on its context: +Workflows use dual concurrency control: per-workflow (based on context) and per-engine (one agent job at a time per AI engine). ```yaml wrap concurrency: group: gh-aw-${{ github.workflow }} - cancel-in-progress: false -``` - -The actual concurrency group pattern varies based on trigger type (includes issue numbers, PR numbers, or branch refs). See [Concurrency Control](/gh-aw/reference/concurrency/) for specific patterns. - -**Benefits:** -- Prevents multiple simultaneous runs for the same context -- Queues work sequentially instead of running in parallel -- Avoids race conditions and duplicate operations - -### Per-Engine Concurrency -Agent jobs use a second concurrency group based on the AI engine: - -```yaml wrap jobs: agent: concurrency: group: gh-aw-copilot - cancel-in-progress: false ``` -**Benefits:** -- Only one agent job runs at a time per engine -- Prevents AI resource exhaustion -- Ensures predictable token usage -- Avoids overwhelming external AI services - -> [!TIP] -> See [Concurrency Control](/gh-aw/reference/concurrency/) for detailed configuration options and customization. - -## Job Timeouts - -Every job has a **maximum execution time** to prevent indefinite running: - -### Workflow-Level Timeout - -Default timeout for all jobs: - -```yaml wrap -jobs: - agent: - timeout-minutes: 360 # 6 hours default -``` +This prevents parallel execution explosions and AI resource exhaustion. See [Concurrency Control](/gh-aw/reference/concurrency/) for trigger-specific patterns. -### Agent Job Timeout +## Timeouts -The agent job (where AI reasoning occurs) has a configurable timeout: +Jobs have maximum execution times (default: 360 minutes). Agent jobs can configure shorter timeouts: ```yaml wrap ---- engine: - id: copilot - timeout: 60 # Minutes (default: 360) ---- + timeout: 60 # Minutes ``` -**Protection provided:** -- Agent cannot run indefinitely even if stuck -- Automatic cancellation after timeout -- Prevents cost overruns from hung processes -- Resource cleanup guaranteed - -### Stop-After Field - -Additional control for workflow runtime limits: +The `stop-after` field provides additional control: ```yaml wrap ---- -stop-after: +48h # Stop workflow after 48 hours ---- +stop-after: +48h # Stop after 48 hours from trigger ``` -**How it works:** -- Evaluated in the agent job's `if:` condition -- Compares current time against workflow start time -- Automatically skips execution if time limit exceeded -- Minimum unit is hours (`+1h`, `+24h`, `+48h`) - -**Example:** - -```yaml wrap ---- -name: Long-Running Analysis -on: - schedule: - - cron: '0 0 * * *' # Daily -stop-after: +6h ---- - -Analysis workflow that automatically stops if not -completed within 6 hours of the scheduled trigger time. -``` - -> [!NOTE] -> The `stop-after` field is checked in the generated workflow action and prevents execution if exceeded, ensuring workflows don't continue beyond their intended window. +This evaluates in the agent job's `if:` condition, preventing execution if the time limit is exceeded. ## Read-Only Agent Tokens -Agents run with **read-only GitHub tokens** by default. They cannot directly: -- Create or modify issues -- Update pull requests -- Post comments -- Change repository settings -- Trigger other workflows - -**Token scope:** +Agents run with read-only permissions. All write operations (creating issues, posting comments, triggering workflows) go through the [safe outputs system](/gh-aw/reference/safe-outputs/), which provides validation, auditing, and rate limiting. ```yaml wrap permissions: - contents: read # Read code only - issues: read # Read issues only - pull-requests: read # Read PRs only + contents: read + issues: read + pull-requests: read ``` -All write operations must go through the **safe outputs system**, which provides validation, auditing, and rate limiting. - -## Safe Outputs Rate Limiting - -The [safe outputs system](/gh-aw/reference/safe-outputs/) provides write capabilities with built-in limits. High-risk operations have **default maximums** to prevent exponential growth: +## Safe Output Limits -### Default Maximum Limits +High-risk operations have default max limits to prevent exponential growth: | Operation | Default Max | Purpose | |-----------|-------------|---------| -| `assign-to-agent` | **1** | Prevent agent spawn cascades | -| `assign-to-bot` | **1** | Prevent bot assignment loops | -| `dispatch-workflow` | **1** | Prevent workflow trigger explosions | -| `create-issue` | **1** | Limit automated issue creation | -| `create-pull-request` | **1** | Limit automated PR creation | - -**Example configuration:** +| `assign-to-agent` | 1 | Prevent agent cascades | +| `assign-to-bot` | 1 | Prevent bot loops | +| `dispatch-workflow` | 1 | Prevent workflow explosions | ```yaml wrap safe-outputs: assign-to-agent: - # Default max: 1 (can be increased if needed) - max: 3 # Allow up to 3 agent assignments - - dispatch-workflow: - # Default max: 1 (prevents cascading triggers) - max: 2 # Allow triggering 2 workflows -``` - -### Why These Limits Matter - -**Without limits:** -```mermaid -graph TD - W1[Workflow 1] -->|assigns agent| I1[Issue 1] - W1 -->|assigns agent| I2[Issue 2] - W1 -->|assigns agent| I3[Issue 3] - I1 -->|triggers| W2[Workflow 2] - I2 -->|triggers| W3[Workflow 3] - I3 -->|triggers| W4[Workflow 4] - W2 -->|assigns 3 more| MORE1[...] - W3 -->|assigns 3 more| MORE2[...] - W4 -->|assigns 3 more| MORE3[...] -``` - -**With default max: 1:** -```mermaid -graph TD - W1[Workflow 1] -->|assigns 1 agent| I1[Issue 1] - I1 -->|triggers| W2[Workflow 2] - W2 -->|assigns 1 agent| I2[Issue 2] - style W1 fill:#e1f5e1 - style W2 fill:#e1f5e1 + max: 3 # Override default if needed ``` -Linear growth instead of exponential explosion. +Without limits, one workflow could spawn three agents, each spawning three more, creating exponential growth. The default max of 1 ensures linear progression. ## Built-In Delays -Critical operations include **mandatory delays** to prevent burst patterns: +Critical operations have hardcoded, non-disableable delays: -### Agent Assignment Delay - -When assigning agents to multiple issues, a **10-second delay** occurs between assignments: +- **Agent assignments**: 10-second delay between each assignment +- **Workflow dispatches**: 5-second delay between each dispatch ```javascript -// From assign_copilot_to_created_issues.cjs -if (i < issueEntries.length - 1) { - core.info("Waiting 10 seconds before processing next agent assignment..."); - await sleep(10000); -} -``` - -**Protection:** -- Prevents spawning many agents simultaneously -- Gives each agent time to start before next assignment -- Reduces API burst load -- Allows monitoring and cancellation if needed - -### Workflow Dispatch Delay +// Agent assignment delay +await sleep(10000); // 10 seconds -Workflow dispatches have a **5-second delay** between triggers: - -```javascript -// From dispatch_workflow.cjs -if (lastDispatchTime > 0) { - const timeSinceLastDispatch = Date.now() - lastDispatchTime; - const delayNeeded = 5000 - timeSinceLastDispatch; - if (delayNeeded > 0) { - core.info(`Waiting ${Math.ceil(delayNeeded / 1000)} seconds before next dispatch...`); - await new Promise(resolve => setTimeout(resolve, delayNeeded)); - } -} +// Workflow dispatch delay +await new Promise(resolve => setTimeout(resolve, 5000)); // 5 seconds ``` -**Protection:** -- Prevents rapid-fire workflow triggering -- Spreads load over time -- Allows cancellation window -- Reduces GitHub API pressure - -> [!IMPORTANT] -> These delays are **hardcoded** in the safe outputs implementation and cannot be disabled. They are essential safety features. +These prevent burst patterns and spread load over time. -## Manual Review with GitHub Environments +## Manual Review Gates -For sensitive operations, you can require **manual approval** before execution using GitHub Environments: +Require manual approval for sensitive operations using GitHub Environments: ```yaml wrap safe-outputs: dispatch-workflow: environment: production # Requires approval - max: 3 ``` -**Configuration steps:** - -1. Create an environment in your repository (Settings → Environments) -2. Add required reviewers -3. Reference the environment in safe output configuration - -**Approval flow:** - -```mermaid -sequenceDiagram - participant Agent - participant SafeOutput - participant Reviewer - participant Action - - Agent->>SafeOutput: Request dispatch-workflow - SafeOutput->>Reviewer: ⏸️ Waiting for approval - Reviewer->>SafeOutput: ✅ Approve - SafeOutput->>Action: Execute workflow dispatch -``` - -**Benefits:** -- Human oversight for critical operations -- Audit trail of approvals -- Ability to reject risky actions -- Compliance with change management policies - -> [!TIP] -> Use environments for operations like: -> - Production workflow dispatches -> - Cross-repository operations -> - Bulk issue/PR creation -> - Security-sensitive actions +Configure environments in repository Settings → Environments, add reviewers, then reference the environment name. Use for production dispatches, cross-repo operations, or security-sensitive actions. ## Rate Limiting Per User -The `rate-limit:` configuration (see [RATE_LIMITING.md](https://github.com/github/gh-aw/blob/main/docs/RATE_LIMITING.md)) prevents individual users from triggering workflows too frequently: +Prevent users from triggering workflows too frequently: ```yaml wrap ---- rate-limit: max: 5 # Maximum runs per window window: 60 # Time window in minutes ---- ``` -**How it works:** -1. Pre-activation job checks recent workflow runs -2. Counts runs by the same user within time window -3. Cancels current run if limit exceeded -4. Prevents both accidental and intentional abuse +The pre-activation job checks recent runs and cancels the current run if the limit is exceeded. See [RATE_LIMITING.md](https://github.com/github/gh-aw/blob/main/docs/RATE_LIMITING.md) for details. -**Example protection:** - -```yaml wrap ---- -name: Expensive Analysis -on: - issue_comment: - types: [created] -rate-limit: - max: 3 - window: 60 ---- -``` - -User cannot trigger more than 3 analysis runs per hour, even by posting multiple comments. - -## Combined Protection Example - -Here's how multiple layers work together: +## Example: Multiple Protection Layers ```yaml wrap --- name: Safe Agent Workflow engine: id: copilot - timeout: 60 # 1 hour max - concurrency: - group: gh-aw-copilot # One at a time + timeout: 60 on: issues: types: [opened] rate-limit: - max: 5 # 5 per hour per user + max: 5 window: 60 -stop-after: +2h # Stop after 2 hours +stop-after: +2h safe-outputs: assign-to-agent: - max: 1 # Only 1 agent assignment - environment: production # Requires approval + max: 1 + environment: production --- - -This workflow has multiple safety layers: -- Rate limited per user -- Concurrency controlled -- Time limited -- Manual approval required -- Single agent assignment only ``` -**Protection layers:** -1. ✅ User can trigger max 5 times/hour (rate-limit) -2. ✅ Only 1 workflow runs at a time (concurrency) -3. ✅ Workflow stops after 2 hours (stop-after) -4. ✅ Agent job limited to 60 minutes (timeout) -5. ✅ Manual approval needed for agent assignment (environment) -6. ✅ Max 1 agent assigned (safe output limit) -7. ✅ 10-second delay before assignment (built-in) -8. ✅ Agent creation won't trigger new workflows (bot non-triggering) +This workflow combines: rate limiting (5/hour per user), concurrency control (one at a time), timeouts (60 min agent, 2h workflow), manual approval (environment), and safe output limits (max 1 agent). The bot non-triggering and built-in delays provide additional protection. ## Best Practices -### Start Conservative - -Begin with strict limits and relax as needed: - -```yaml wrap -# Initial configuration - very safe -safe-outputs: - assign-to-agent: - max: 1 # Start with 1 - dispatch-workflow: - max: 1 # Start with 1 - -rate-limit: - max: 3 # Low frequency - window: 60 -``` - -Monitor behavior, then increase limits if justified. - -### Use Environments for High-Risk Operations - -Require manual approval for operations that: -- Trigger other workflows -- Create many resources -- Cross repository boundaries -- Affect production systems - -### Monitor and Audit - -Regularly review: -- Workflow run history -- Safe output execution logs -- Rate limit cancellations -- Timeout occurrences - -Look for patterns indicating configuration adjustments needed. - -### Layer Controls - -Don't rely on a single protection mechanism. Use multiple: -- Rate limiting **AND** concurrency control -- Timeouts **AND** stop-after -- Safe output limits **AND** environments - -Defense-in-depth ensures reliability. +Start with conservative limits and increase as needed. Use environments for high-risk operations (workflow dispatches, cross-repo operations, production systems). Layer multiple controls: rate limiting with concurrency, timeouts with stop-after, safe output limits with environments. Monitor workflow runs, safe output logs, and rate limit cancellations to identify needed adjustments. ## Troubleshooting -### Workflows Not Running - -**Symptom:** Workflow run immediately cancelled - -**Check:** -1. Rate limit exceeded? Look for "rate limit" in pre-activation logs -2. Concurrency queue full? Check other running workflows -3. Stop-after time exceeded? Verify workflow start time - -### Agent Assignments Slow - -**Symptom:** Multiple agent assignments take longer than expected - -**Explanation:** Built-in 10-second delays are working as designed. If assigning 5 agents, expect ~40 seconds total (4 delays). - -**This is intentional** to prevent overwhelming the system. - -### Workflow Dispatch Not Triggering +**Workflow immediately cancelled**: Check rate limit in pre-activation logs, verify concurrency queue, or confirm stop-after hasn't exceeded. -**Symptom:** dispatch-workflow safe output runs but target workflow doesn't start +**Agent assignments slow**: Built-in 10-second delays are intentional. Five agents = ~40 seconds total. -**Check:** -1. Max dispatch limit (default: 1) - only first dispatch succeeds -2. 5-second delay between dispatches -3. Target workflow `on: workflow_dispatch` configuration -4. Environment approval still pending +**Workflow dispatch not triggering**: Verify max dispatch limit (default: 1), check 5-second delay, confirm target workflow has `on: workflow_dispatch`, or check pending environment approvals. ## Related Documentation From ebaa8bdfd2cc1713acdbfbd3b3fda8b01e17db5f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:45:03 +0000 Subject: [PATCH 5/7] Fix timeout field and add complete rate-limit frontmatter details Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../docs/reference/rate-limiting-controls.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/src/content/docs/reference/rate-limiting-controls.md b/docs/src/content/docs/reference/rate-limiting-controls.md index 5963212999..dd68f3b1b7 100644 --- a/docs/src/content/docs/reference/rate-limiting-controls.md +++ b/docs/src/content/docs/reference/rate-limiting-controls.md @@ -37,20 +37,19 @@ This prevents parallel execution explosions and AI resource exhaustion. See [Con ## Timeouts -Jobs have maximum execution times (default: 360 minutes). Agent jobs can configure shorter timeouts: +Jobs have maximum execution times (default: 360 minutes) controlled by the top-level `timeout-minutes` field: ```yaml wrap -engine: - timeout: 60 # Minutes +timeout-minutes: 120 # Apply 120-minute timeout to all jobs ``` -The `stop-after` field provides additional control: +The `stop-after` field provides additional control for when workflows should stop running: ```yaml wrap stop-after: +48h # Stop after 48 hours from trigger ``` -This evaluates in the agent job's `if:` condition, preventing execution if the time limit is exceeded. +This evaluates in the agent job's `if:` condition, preventing execution if the time limit is exceeded. Supports absolute dates and relative time deltas (minimum unit is hours). ## Read-Only Agent Tokens @@ -112,15 +111,16 @@ Configure environments in repository Settings → Environments, add reviewers, t ## Rate Limiting Per User -Prevent users from triggering workflows too frequently: +The `rate-limit` frontmatter field prevents users from triggering workflows too frequently: ```yaml wrap rate-limit: - max: 5 # Maximum runs per window - window: 60 # Time window in minutes + max: 5 # Required: Maximum runs per window (1-10) + window: 60 # Optional: Time window in minutes (default: 60, max: 180) + events: [workflow_dispatch, issue_comment] # Optional: Specific events (auto-inferred if omitted) ``` -The pre-activation job checks recent runs and cancels the current run if the limit is exceeded. See [RATE_LIMITING.md](https://github.com/github/gh-aw/blob/main/docs/RATE_LIMITING.md) for details. +The pre-activation job checks recent runs and cancels the current run if the limit is exceeded. See [RATE_LIMITING.md](https://github.com/github/gh-aw/blob/main/docs/RATE_LIMITING.md) for complete details including event auto-inference. ## Example: Multiple Protection Layers @@ -129,14 +129,14 @@ The pre-activation job checks recent runs and cancels the current run if the lim name: Safe Agent Workflow engine: id: copilot - timeout: 60 +timeout-minutes: 60 # Job timeout on: issues: types: [opened] rate-limit: max: 5 window: 60 -stop-after: +2h +stop-after: +2h # Workflow time limit safe-outputs: assign-to-agent: max: 1 @@ -144,7 +144,7 @@ safe-outputs: --- ``` -This workflow combines: rate limiting (5/hour per user), concurrency control (one at a time), timeouts (60 min agent, 2h workflow), manual approval (environment), and safe output limits (max 1 agent). The bot non-triggering and built-in delays provide additional protection. +This workflow combines: rate limiting (5/hour per user), concurrency control (one at a time), timeouts (60 min job, 2h workflow), manual approval (environment), and safe output limits (max 1 agent). The bot non-triggering and built-in delays provide additional protection. ## Best Practices From 17ccbd29095bb087213f8f56d54eb3abf69ce3ab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:58:31 +0000 Subject: [PATCH 6/7] Add ignored-roles field to rate-limit documentation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/ai-moderator.lock.yml | 1 + .github/workflows/auto-triage-issues.lock.yml | 1 + .github/workflows/example-custom-error-patterns.lock.yml | 1 + .github/workflows/workflow-generator.lock.yml | 1 + docs/src/content/docs/agent-factory-status.mdx | 1 - docs/src/content/docs/reference/rate-limiting-controls.md | 5 ++++- 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml index fdacecbdf4..f3bf929dd7 100644 --- a/.github/workflows/ai-moderator.lock.yml +++ b/.github/workflows/ai-moderator.lock.yml @@ -1015,6 +1015,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issue_comment,issues,workflow_dispatch" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/auto-triage-issues.lock.yml b/.github/workflows/auto-triage-issues.lock.yml index 9d34e93bc6..676e352e53 100644 --- a/.github/workflows/auto-triage-issues.lock.yml +++ b/.github/workflows/auto-triage-issues.lock.yml @@ -1072,6 +1072,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issues,workflow_dispatch" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/example-custom-error-patterns.lock.yml b/.github/workflows/example-custom-error-patterns.lock.yml index 890c0df337..e20898d296 100644 --- a/.github/workflows/example-custom-error-patterns.lock.yml +++ b/.github/workflows/example-custom-error-patterns.lock.yml @@ -509,6 +509,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issues" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml index 010f60e827..919447be03 100644 --- a/.github/workflows/workflow-generator.lock.yml +++ b/.github/workflows/workflow-generator.lock.yml @@ -1140,6 +1140,7 @@ jobs: GH_AW_RATE_LIMIT_MAX: "5" GH_AW_RATE_LIMIT_WINDOW: "60" GH_AW_RATE_LIMIT_EVENTS: "issues" + GH_AW_RATE_LIMIT_IGNORED_ROLES: "admin,maintain,write" with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/docs/src/content/docs/agent-factory-status.mdx b/docs/src/content/docs/agent-factory-status.mdx index 96d79fc6b3..398f7ce702 100644 --- a/docs/src/content/docs/agent-factory-status.mdx +++ b/docs/src/content/docs/agent-factory-status.mdx @@ -144,7 +144,6 @@ These are experimental agentic workflows used by the GitHub Next team to learn, | [Test Create PR Error Handling](https://github.com/github/gh-aw/blob/main/.github/workflows/test-create-pr-error-handling.md) | claude | [![Test Create PR Error Handling](https://github.com/github/gh-aw/actions/workflows/test-create-pr-error-handling.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-create-pr-error-handling.lock.yml) | - | - | | [Test Dispatcher Workflow](https://github.com/github/gh-aw/blob/main/.github/workflows/test-dispatcher.md) | copilot | [![Test Dispatcher Workflow](https://github.com/github/gh-aw/actions/workflows/test-dispatcher.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-dispatcher.lock.yml) | - | - | | [Test Project URL Explicit Requirement](https://github.com/github/gh-aw/blob/main/.github/workflows/test-project-url-default.md) | copilot | [![Test Project URL Explicit Requirement](https://github.com/github/gh-aw/actions/workflows/test-project-url-default.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-project-url-default.lock.yml) | - | - | -| [Test Rate Limiting with Ignored Roles](https://github.com/github/gh-aw/blob/main/.github/workflows/test-rate-limit-ignored-roles.md) | copilot | [![Test Rate Limiting with Ignored Roles](https://github.com/github/gh-aw/actions/workflows/test-rate-limit-ignored-roles.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-rate-limit-ignored-roles.lock.yml) | - | - | | [Test Workflow](https://github.com/github/gh-aw/blob/main/.github/workflows/test-workflow.md) | copilot | [![Test Workflow](https://github.com/github/gh-aw/actions/workflows/test-workflow.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/test-workflow.lock.yml) | - | - | | [The Daily Repository Chronicle](https://github.com/github/gh-aw/blob/main/.github/workflows/daily-repo-chronicle.md) | copilot | [![The Daily Repository Chronicle](https://github.com/github/gh-aw/actions/workflows/daily-repo-chronicle.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/daily-repo-chronicle.lock.yml) | `0 16 * * 1-5` | - | | [The Great Escapi](https://github.com/github/gh-aw/blob/main/.github/workflows/firewall-escape.md) | copilot | [![The Great Escapi](https://github.com/github/gh-aw/actions/workflows/firewall-escape.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/firewall-escape.lock.yml) | - | - | diff --git a/docs/src/content/docs/reference/rate-limiting-controls.md b/docs/src/content/docs/reference/rate-limiting-controls.md index dd68f3b1b7..c45a8e8b1f 100644 --- a/docs/src/content/docs/reference/rate-limiting-controls.md +++ b/docs/src/content/docs/reference/rate-limiting-controls.md @@ -118,9 +118,12 @@ rate-limit: max: 5 # Required: Maximum runs per window (1-10) window: 60 # Optional: Time window in minutes (default: 60, max: 180) events: [workflow_dispatch, issue_comment] # Optional: Specific events (auto-inferred if omitted) + ignored-roles: [admin, maintain] # Optional: Roles exempt from rate limiting (default: [admin, maintain, write]) ``` -The pre-activation job checks recent runs and cancels the current run if the limit is exceeded. See [RATE_LIMITING.md](https://github.com/github/gh-aw/blob/main/docs/RATE_LIMITING.md) for complete details including event auto-inference. +The pre-activation job checks recent runs and cancels the current run if the limit is exceeded. + +**Role exemptions**: By default, users with `admin`, `maintain`, or `write` roles are exempt from rate limiting. To apply rate limiting to all users including admins, set `ignored-roles: []`. ## Example: Multiple Protection Layers From 89321a43985b9cdf8a23f4ef346d99e5f2f3b6e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Feb 2026 00:12:50 +0000 Subject: [PATCH 7/7] Add Rate Limiting Controls to Astro sidebar configuration Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- docs/astro.config.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index e33cbc3169..6135f4f130 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -211,6 +211,7 @@ export default defineConfig({ { label: 'MCP Gateway', link: '/reference/mcp-gateway/' }, { label: 'Network Access', link: '/reference/network/' }, { label: 'Permissions', link: '/reference/permissions/' }, + { label: 'Rate Limiting Controls', link: '/reference/rate-limiting-controls/' }, { label: 'Safe Inputs', link: '/reference/safe-inputs/' }, { label: 'Safe Outputs', link: '/reference/safe-outputs/' }, { label: 'Schedule Syntax', link: '/reference/schedule-syntax/' },