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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ai-moderator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .github/workflows/auto-triage-issues.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .github/workflows/example-custom-error-patterns.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .github/workflows/workflow-generator.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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/' },
Expand Down
1 change: 0 additions & 1 deletion docs/src/content/docs/agent-factory-status.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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) | - | - |
Expand Down
170 changes: 170 additions & 0 deletions docs/src/content/docs/reference/rate-limiting-controls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
---
Copy link
Contributor

Choose a reason for hiding this comment

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

@copilot add file to astro configuration in TOC

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added to sidebar in 89321a4. The "Rate Limiting Controls" entry now appears in the Reference section between "Permissions" and "Safe Inputs" (alphabetical order).

title: Rate Limiting Controls
description: Built-in protections to prevent runaway agentic workflows and exponential growth.
sidebar:
order: 1450
---

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.

## Bot Non-Triggering

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]
```

This workflow won't be triggered by issues created by safe outputs.
Comment on lines +12 to +20
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The bot non-triggering explanation is too absolute. Safe outputs can be configured to use a custom github-token, in which case the actor may not be github-actions[bot] and the resulting issue/comment can trigger other workflows. Consider qualifying this section to explicitly refer to operations performed with GITHUB_TOKEN/github-actions[bot], and mention that custom tokens may re-enable triggering.

Copilot uses AI. Check for mistakes.

## Concurrency Groups

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 }}

jobs:
agent:
concurrency:
group: gh-aw-copilot
Comment on lines +28 to +33
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The concurrency example doesn’t match the compiler’s generated patterns. Workflow-level concurrency groups include context (issue/PR number or ref) rather than only ${{ github.workflow }} (see pkg/workflow/concurrency.go:128-156), and job-level concurrency isn’t a fixed gh-aw-copilot group by default. Update the snippet to reflect the actual generated groups or use an abbreviated example that links to the Concurrency Control page without implying specific group values.

Suggested change
group: gh-aw-${{ github.workflow }}
jobs:
agent:
concurrency:
group: gh-aw-copilot
# Workflow-level concurrency group is generated from workflow context
group: ${{ ... }}
jobs:
agent:
concurrency:
# Job-level concurrency group is generated per engine/trigger
group: ${{ ... }}

Copilot uses AI. Check for mistakes.
```

This prevents parallel execution explosions and AI resource exhaustion. See [Concurrency Control](/gh-aw/reference/concurrency/) for trigger-specific patterns.

## Timeouts

Jobs have maximum execution times (default: 360 minutes) controlled by the top-level `timeout-minutes` field:

```yaml wrap
timeout-minutes: 120 # Apply 120-minute timeout to all jobs
Comment on lines +40 to +43
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The stated default timeout is incorrect for this project. timeout-minutes defaults to 20 minutes for agentic workflows (see pkg/constants/constants.go:462-463 and schema description in pkg/parser/schemas/main_workflow_schema.json:1789-1793), not 360 minutes. Please update the default value and clarify what scope this field affects in compiled workflows.

Suggested change
Jobs have maximum execution times (default: 360 minutes) controlled by the top-level `timeout-minutes` field:
```yaml wrap
timeout-minutes: 120 # Apply 120-minute timeout to all jobs
Jobs have maximum execution times (default: 20 minutes for agentic workflows) controlled by the top-level `timeout-minutes` field in the compiled workflow:
```yaml wrap
timeout-minutes: 120 # Apply 120-minute job timeout to all jobs in the compiled workflow

Copilot uses AI. Check for mistakes.
```

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. Supports absolute dates and relative time deltas (minimum unit is hours).

## Read-Only Agent Tokens

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
issues: read
pull-requests: read
```

## Safe Output Limits

High-risk operations have default max limits to prevent exponential growth:

| Operation | Default Max | Purpose |
|-----------|-------------|---------|
| `assign-to-agent` | 1 | Prevent agent cascades |
| `assign-to-bot` | 1 | Prevent bot loops |
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

assign-to-bot does not appear to be a supported safe output type (it’s not in the safe-outputs schema or config structs). Consider removing it from this table, or replacing it with an actual safe output type (for example assign-to-user) if that’s what was intended.

Suggested change
| `assign-to-bot` | 1 | Prevent bot loops |
| `assign-to-user` | 1 | Prevent bot loops |

Copilot uses AI. Check for mistakes.
| `dispatch-workflow` | 1 | Prevent workflow explosions |

```yaml wrap
safe-outputs:
assign-to-agent:
max: 3 # Override default if needed
```

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 have hardcoded, non-disableable delays:

- **Agent assignments**: 10-second delay between each assignment
- **Workflow dispatches**: 5-second delay between each dispatch

```javascript
// Agent assignment delay
await sleep(10000); // 10 seconds

// Workflow dispatch delay
await new Promise(resolve => setTimeout(resolve, 5000)); // 5 seconds
```

These prevent burst patterns and spread load over time.

## Manual Review Gates

Require manual approval for sensitive operations using GitHub Environments:

```yaml wrap
safe-outputs:
dispatch-workflow:
environment: production # Requires approval
Comment on lines +105 to +107
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The manual review gate example uses safe-outputs.dispatch-workflow.environment, but environment isn’t a supported field for safe output types in the schema (safe outputs support max and github-token, plus type-specific fields). Manual approvals are configured via on.manual-approval: <environment> (see docs/src/content/docs/reference/triggers.md). Please update this section (and the later example) to use manual-approval/job environment in the supported way.

Suggested change
safe-outputs:
dispatch-workflow:
environment: production # Requires approval
on:
manual-approval: production # Requires approval
jobs:
protected-dispatch:
environment: production

Copilot uses AI. Check for mistakes.
```

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` frontmatter field prevents users from triggering workflows too frequently:

```yaml wrap
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.

**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

```yaml wrap
---
name: Safe Agent Workflow
engine:
id: copilot
timeout-minutes: 60 # Job timeout
on:
issues:
types: [opened]
rate-limit:
max: 5
window: 60
stop-after: +2h # Workflow time limit
safe-outputs:
assign-to-agent:
max: 1
environment: production
Comment on lines +139 to +146
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

This full example uses stop-after at the top level and includes safe-outputs.assign-to-agent.environment, neither of which matches the documented schema (stop-after is under on:, and safe-outputs types don’t accept environment). Adjust the example to use on.stop-after and on.manual-approval (or another supported gating mechanism) so readers can copy/paste it successfully.

This issue also appears on line 46 of the same file.

Suggested change
rate-limit:
max: 5
window: 60
stop-after: +2h # Workflow time limit
safe-outputs:
assign-to-agent:
max: 1
environment: production
stop-after: +2h # Workflow time limit
manual-approval:
required: true
environment: production
rate-limit:
max: 5
window: 60
safe-outputs:
assign-to-agent:
max: 1

Copilot uses AI. Check for mistakes.
---
```

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

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

**Workflow immediately cancelled**: Check rate limit in pre-activation logs, verify concurrency queue, or confirm stop-after hasn't exceeded.

**Agent assignments slow**: Built-in 10-second delays are intentional. Five agents = ~40 seconds total.

**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

- [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
Loading