Note
The action is currently in beta, under active development
A GitHub Action that starts Netlify Agent Runners agent runs directly from GitHub issues and pull requests using @netlify mentions.
- Create an issue or comment on a PR with
@netlifyfollowed by your prompt - The action picks up the trigger, adds a π reaction, and creates an in-progress status comment
- Netlify Agent Runners creates an agent run to build or modify your site based on the prompt
- On completion, the action posts a full result comment, then updates the status comment with a short summary and a link to that result
- If triggered from an issue, a PR is automatically created with the changes
@netlify Build a landing page for a coffee shop with a menu and contact form
@netlify claude Add a dark mode toggle
@netlify codex Make the hero section responsive
@netlify gemini Add a testimonials section
The default agent is codex. Specify claude, codex, or gemini after @netlify to choose an agent.
- Install the netlify-coding GitHub App on your repository
- Create a Netlify site linked to your repo (
netlify init) - Generate a Netlify personal access token
Go to Settings > Secrets and variables > Actions and add:
| Secret | Description |
|---|---|
NETLIFY_AUTH_TOKEN |
Your Netlify personal access token |
NETLIFY_SITE_ID |
Your Netlify site ID (from Site configuration > General) |
Create .github/workflows/netlify-agents.yml in your repository:
name: Netlify Agent Runners
on:
workflow_dispatch:
inputs:
trigger_text:
description: 'Prompt for the agent run'
required: true
type: string
default: '@netlify'
actor:
description: 'Actor triggering the agent'
required: true
type: string
agent:
description: 'Agent to use (claude, codex, gemini)'
required: false
type: string
default: 'codex'
pull_request_target:
types: [opened, synchronize, reopened]
pull_request_review_comment:
types: [created]
pull_request_review:
types: [submitted, edited]
issues:
types: [opened, assigned, edited]
issue_comment:
types: [created, edited]
concurrency:
group: netlify-${{ github.repository }}-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
cancel-in-progress: false
jobs:
netlify-agent:
runs-on: ubuntu-latest
timeout-minutes: 25
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: netlify-labs/agent-runner-action@v1
with:
netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
netlify-site-id: ${{ secrets.NETLIFY_SITE_ID }}Create a new issue:
Title: Build a portfolio site
Body: @netlify claude Create a modern portfolio with a projects grid and contact form
Or comment @netlify make it blue on an existing PR.
| Input | Required | Default | Description |
|---|---|---|---|
netlify-auth-token |
Yes | β | Netlify personal access token |
netlify-site-id |
Yes | β | Netlify site ID |
github-token |
No | github.token |
GitHub token for API calls |
allowed-users |
No | '' |
Comma-separated usernames allowed to trigger (empty = repo collaborators) |
default-agent |
No | codex |
Default agent (claude, codex, or gemini) |
default-model |
No | codex |
Backward-compatible alias for default-agent |
manage-labels |
No | false |
Auto-create and apply labels on agent runs |
dry-run |
No | false |
Start an agent run but skip commit/PR creation |
preflight-only |
No | false |
Validate setup and exit without creating/resuming an agent run |
timeout-minutes |
No | 10 |
Max minutes to wait for agent completion |
netlify-cli-version |
No | 24.8.1 |
Netlify CLI version to install |
debug |
No | false |
Enable debug logging of API responses |
timezone |
No | America/Los_Angeles |
Timezone used for date/time rendering in comments |
dry-run: 'true'still starts an agent run (external Netlify calls still happen), but it skips branch commits and pull request creation.preflight-only: 'true'validates setup and permissions, then exits before creating/resuming any agent run.- If both are set to
true,preflight-onlybehavior wins and no agent is started.
steps:
- uses: netlify-labs/agent-runner-action@v1
id: preflight
with:
netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
netlify-site-id: ${{ secrets.NETLIFY_SITE_ID }}
preflight-only: 'true' # setup validation only, no agent run
- uses: netlify-labs/agent-runner-action@v1
id: preview
with:
netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
netlify-site-id: ${{ secrets.NETLIFY_SITE_ID }}
dry-run: 'true' # agent runs, but no commits/PR creationIf preflight-only fails, inspect preflight-summary and preflight-json outputs and check:
netlify-auth-tokenis present and validnetlify-site-idmatches a site your token can accessdefault-agentselects one of the supported agents:claude,codex, orgeminidefault-modelremains supported as a backward-compatible aliastimeout-minutesis a positive integer- workflow permissions include
contents: write,pull-requests: write, andissues: write
Use these outputs in subsequent workflow steps for custom automation:
| Output | Description |
|---|---|
agent-id |
Agent run ID |
outcome |
success, failure, or timeout |
agent-result |
Agent result summary text |
agent-pr-url |
Pull request URL (if created) |
agent-deploy-url |
Deploy preview URL |
agent |
Agent that was used |
model |
Backward-compatible alias for agent |
trigger-text |
Cleaned trigger text / prompt |
is-pr |
Whether triggered from a PR (true/false) |
issue-number |
Issue or PR number |
is-dry-run |
Whether the run used preview mode (true/false) |
preflight-ok |
Whether preflight validation passed (true/false) |
preflight-json |
Serialized preflight result payload (ok, checks, warnings, failures) |
preflight-summary |
Human-readable summary of preflight status |
should-continue |
Whether workflow execution should continue into agent runtime |
failure-category |
Preflight/runtime failure taxonomy category when available |
failure-stage |
Preflight/runtime failure stage when available |
agent-error |
Sanitized runtime error summary emitted by agent orchestration |
steps:
- uses: netlify-labs/agent-runner-action@v1
id: agent
with:
netlify-auth-token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
netlify-site-id: ${{ secrets.NETLIFY_SITE_ID }}
# preflight-only: 'false' # Validate setup and stop before agent execution
- name: Run tests on agent PR
if: steps.agent.outputs.outcome == 'success' && steps.agent.outputs.agent-pr-url != ''
run: echo "Agent created PR: ${{ steps.agent.outputs.agent-pr-url }}"Use the local simulator to preview action decisions from fixtures without GitHub Actions or live Netlify calls. The simulate package script wraps src/simulate.js.
# Human-readable run/skip decision for a fixture
bun run simulate --fixture fixtures/events/issue-comment-on-pr.json
# JSON for scripts and test debugging
bun run simulate --fixture fixtures/events/workflow-dispatch.json --format json
# Markdown for copying a scenario report into an issue or PR
bun run simulate --fixture fixtures/events/issue-comment-on-pr.json --state-fixture /tmp/state.json --format markdownNotes:
--fixtureis required.--state-fixtureis optional and can inject prior status/PR state for runner recovery paths.--formatsupportshuman(default),json, andmarkdown.- Each report includes the scenario name, run/skip decision, context, recovered state, and rendered comments.
- Reconciliation warnings are included in simulator output under
Warnings.
Use act to run the GitHub Actions CI workflow locally before pushing.
bun run act:list
bun run act:ci
bun run act:ci:prThe repo includes .actrc plus push and pull request payloads under .act/. Normal act runs require Docker. On macOS, start Docker Desktop first. If Docker is unavailable, bun run act:ci:host runs the same job on the host machine as a faster smoke check, but it is less representative than the container-backed runner.
- Status comment β one mutable current-state comment with a short summary, deploy/agent/log links, and hidden state markers used to resume follow-up runs
- Result comments β one immutable full narrative comment per Netlify session run, including the prompt, result prose, screenshot, and links
- History TOC β one compact PR-only table of contents linking to result comments, newest-first
- Issue redirect β after a PR is created from an issue, a note directs users to the PR
After the first run creates a PR, add follow-up @netlify comments on the PR. The agent iterates on existing code. Commenting on the original issue shows a redirect to the PR.
- Only repository collaborators, members, and owners can trigger agent runs
- Bot accounts (
github-actions[bot],netlify-coding[bot]) are excluded - Concurrency control ensures one run per issue/PR at a time
- The
allowed-usersinput can further restrict access to specific users - Common
@netlifytypos (@nelify,@netlfy, etc.) are recognised - Only status comments carry runner/session state markers. Result comments are scrubbed so user or agent prose cannot reflect status/history/state markers into bot-authored comments; they carry only a result identifier marker for the PR history TOC.
The example workflow uses the pull_request_target trigger so that PRs opened from forks can trigger agent runs. This trigger is powerful: it runs in the context of the base repository with access to repository secrets (NETLIFY_AUTH_TOKEN) and a write-scoped GITHUB_TOKEN. Combined with checking out the PR's head commit, this is the pattern GitHub Security Lab describes as a "pwn request" β if misused, it lets a fork PR author exfiltrate secrets or push to your repo.
This action is safe under that trigger because:
- Author-association gate. Before checkout, the action checks
author_associationon the event and drops anything that isn'tCOLLABORATOR,MEMBER,OWNER, or a user with write permission on the repo. Fork PRs from outside contributors are skipped. - No PR code is executed on the runner. After checkout, the workflow only inspects
package.jsonfor framework detection, runsgit diffagainst the base branch, installs a pinned Netlify CLI, and hands the prompt to Netlify's remote agent service. The agent itself runs on Netlify infrastructure, not on your runner.
If you fork this workflow, do not add steps that execute PR-supplied code (e.g. npm install against the PR's package.json, running the project's tests/linter/build, or any tool that loads config files from the workspace). Any such step turns this from "trusted-only trigger that calls a remote API" into a credential exfiltration vector. If you need to run PR code, switch to the two-workflow pull_request + workflow_run pattern described in the GitHub Security Lab article above.