| name | github-aw-syntax |
| description | Complete reference for GitHub Agentic Workflows (gh-aw) frontmatter schema, engine configuration, network access, tools, and imports syntax. You MUST load this skill when writing or debugging Agentic Workflow files. |
| license | MIT |
github-aw-syntax
Reference for GitHub Agentic Workflows frontmatter schema, engines, networking, tools, and safe-outputs.
WHEN TO USE
- When writing, editing, or debugging the YAML frontmatter of a
.md Agentic Workflow file.
- To configure MCP server tools, permissions, network allowlists, or safe-outputs for an agent.
- When optimizing the caching or runtime environments of a GitHub Agentic Workflow.
WHEN NOT TO USE
- For standard GitHub Actions workflows (
.github/workflows/*.yml) that do not use the gh-aw engine.
- When writing the natural language instructions inside the workflow body (use
ai-prompt-writer instead).
- For troubleshooting execution failures (use
gh-aw-troubleshooting instead).
Common Pitfalls
- Silent Schema Ignorance: Misspelling a configuration key in the frontmatter, which the compiler silently ignores unless
gh aw compile --verbose is used.
- Network Egress Blocking: Attempting to call an external API without explicitly adding its domain to the
network.allowed array, resulting in a blocked connection.
- Granting Write Permissions: Adding
issues: write or contents: write to the permissions: block instead of properly using safe-outputs, which violates the security model.
Core Principles
- No Write Permissions in Main Job: Never use
issues: write, pull-requests: write, or contents: write. Write operations must use safe-outputs.
- Prefer
gh-proxy: For GitHub API tool access, use mode: "gh-proxy" to leverage gh CLI directly for reads.
- Narrow Bash Allowlist: For PR-triggered workflows, restrict
bash tools to safe commands (e.g., [find, cat, grep, jq]).
Use ["*"] only for trusted internal schedules.
- Explicit Ecosystems: Always specify target language ecosystems (e.g.,
node, python, go) in network.allowed alongside defaults to prevent package manager blocks.
Core GitHub Actions Fields
Frontmatter Elements - Trigger Events (on:)
Below is a comprehensive reference to all available frontmatter fields for GitHub Agentic Workflows.
The on: section uses standard GitHub Actions syntax to define workflow triggers, with additional fields for security and approval controls:
- Standard GitHub Actions triggers (push, pull_request, issues, schedule, etc.)
reaction: - Add emoji reactions to triggering items
status-comment: - Post a started/completed comment with a workflow run link (automatically enabled for slash_command and label_command triggers; must be explicitly set to true for other trigger types). Accepts a boolean or an object with optional issues, pull-requests, and discussions toggle fields to selectively disable status comments for specific target types.
stop-after: - Automatically disable triggers after a deadline
manual-approval: - Require manual approval using environment protection rules
forks: - Configure fork filtering for pull_request triggers
skip-roles: - Skip workflow execution for specific repository roles
skip-bots: - Skip workflow execution for specific GitHub actors
skip-author-associations: - Skip execution for configured event + author_association combinations
skip-if-match: - Skip execution when a search query has matches (supports scope: none; use top-level on.github-token / on.github-app for custom auth)
skip-if-no-match: - Skip execution when a search query has no matches (supports scope: none; use top-level on.github-token / on.github-app for custom auth)
steps: - Inject custom deterministic steps into the pre-activation job (saves one workflow job vs. multi-job pattern)
permissions: - Grant additional GitHub token scopes to the pre-activation job (for use with on.steps: API calls)
needs: - Add custom job dependencies that both pre_activation and activation must wait for
github-token: - Custom token for activation job reactions, status comments, and skip-if search queries
github-app: - GitHub App for minting a short-lived token used by the activation job and all skip-if search steps
Agentic Workflow Specific Fields
-
description: - Human-readable workflow description (string)
-
source: - Workflow origin tracking in format owner/repo/path@ref (string)
-
labels: - Array of labels to categorize and organize workflows (array)
- Labels filter workflows in status/list commands
- Example:
labels: [automation, security, daily]
-
metadata: - Custom key-value pairs compatible with custom agent spec (object)
- Key names limited to 64 characters
- Values limited to 1024 characters
- Example:
metadata: { team: "platform", priority: "high" }
-
github-token: - Default GitHub token for workflow (must use ${{ secrets.* }} syntax).
- Breaking Change (v0.24.0+): The default
secrets.GITHUB_TOKEN fallback has been removed from Copilot-related operations
(including create-agent-task, assigning Copilot to issues, and adding Copilot as PR reviewer) because it lacks required permissions,
causing silent failures. Users must now configure a Personal Access Token (PAT) as either COPILOT_GITHUB_TOKEN or GH_AW_GITHUB_TOKEN secret.
As of v0.26+, GH_AW_COPILOT_TOKEN is no longer supported; use COPILOT_GITHUB_TOKEN instead.
-
on.roles: - Repository access roles that can trigger workflow (array or "all")
- Default:
[admin, maintainer, write]
- Available roles:
admin, maintainer, write, read, all
-
bots: - Bot identifiers allowed to trigger workflow regardless of role permissions (array)
- Example:
bots: [dependabot[bot], renovate[bot], github-actions[bot]]
- Bot must be active (installed) on repository to trigger workflow
-
strict: - Enable enhanced validation for production workflows (boolean, defaults to )
Cache Configuration
The cache: field supports the same syntax as the GitHub Actions actions/cache action:
Single Cache:
cache:
key: node-modules-${{ hashFiles('package-lock.json') }}
path: node_modules
restore-keys: |
node-modules-
Multiple Caches:
cache:
- key: node-modules-${{ hashFiles('package-lock.json') }}
path: node_modules
restore-keys: |
node-modules-
- key: build-cache-${{ github.sha }}
path:
- dist
- .cache
restore-keys:
- build-cache-
fail-on-cache-miss: false
Supported Cache Parameters:
key: - Cache key (required)
path: - Files/directories to cache (required, string or array)
restore-keys: - Fallback keys (string or array)
upload-chunk-size: - Chunk size for large files (integer)
fail-on-cache-miss: - Fail if cache not found (boolean)
lookup-only: - Only check cache existence (boolean)
Cache steps are automatically added to the workflow job and the cache configuration is removed from the final .lock.yml file.
Memory configuration: For detailed documentation on cache-memory:, repo-memory:, and comment-memory: configuration including advanced options and use cases, see memory.md.
Available Coding Agents
Set engine: in your workflow frontmatter and configure the corresponding secret:
Copilot CLI is the default — engine: can be omitted when using Copilot. See the linked authentication docs for secret setup instructions.
Engine Feature Comparison
Not all features are available across all engines. The table below summarizes per-engine support for commonly used workflow options:
| Feature | Copilot | Claude | Codex | Gemini | Crush | OpenCode | Pi |
|---|
max-runs (AWF invocation cap) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
max-turns | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
max-continuations | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
tools.web-fetch | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
tools.web-search | via MCP | via MCP | ✅ (opt-in) | via MCP | via MCP | via MCP | via MCP |
engine.agent (custom agent file) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
engine.api-target (custom endpoint) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Notes:
max-runs is a top-level frontmatter field that maps to apiProxy.maxRuns and is supported by all engines.
max-runs defaults to 500 and max-effective-tokens defaults to 25000000 when omitted.
max-turns limits the number of AI chat iterations per run (Claude only).
max-continuations enables autopilot mode with multiple consecutive runs (Copilot only).
web-search for Codex is disabled by default; add tools: web-search: to enable it. Other engines use a third-party MCP server — see Using Web Search.
engine.agent references a .github/agents/ file for custom Copilot agent behavior. See Copilot Custom Configuration.
engine.bare disables automatic context loading (memory files, custom instructions). See Bare Mode.
engine.harness allows replacing the built-in Copilot harness script. See Custom Harness Script.
Extended Coding Agent Configuration
Workflows can specify extended configuration for the coding agent:
engine:
id: copilot
version: latest # defaults to latest
model: gpt-5 # example override; omit to use engine default
command: /usr/local/bin/copilot # custom executable path
args: ["--add-dir", "/workspace"] # custom CLI arguments
agent: agent-id # custom agent file identifier
api-target: api.acme.ghe.com # custom API endpoint hostname (GHEC/GHES)
Copilot Custom Configuration
Use agent to reference a custom agent file in .github/agents/ (omit the .agent.md extension):
engine:
id: copilot
agent: technical-doc-writer # .github/agents/technical-doc-writer.agent.md
See Copilot Agent Files for details.
Engine Environment Variables
All engines support custom environment variables through the env field:
engine:
id: copilot
env:
DEBUG_MODE: "true"
AWS_REGION: us-west-2
CUSTOM_API_ENDPOINT: https://api.example.com
Environment variables can also be defined at workflow, job, step, and other scopes. See Environment Variables for complete documentation on precedence and all 13 env scopes.
Tool Configuration
General Tools
tools:
edit: # File editing (required to write to files)
web-fetch: # Web content fetching
web-search: # Web searching
bash: # Shell commands
- "gh label list:*"
- "gh label view:*"
- "git status"
Custom MCP Tools
Stdio MCP servers must be Docker-based (use container: + entrypoint:). For Node/Python servers already installed on the runner, use HTTP transport instead:
# Stdio (Docker-based)
mcp-servers:
my-custom-tool:
container: "ghcr.io/my-org/my-tool:latest"
entrypoint: "my-tool"
allowed:
- custom_function_1
- custom_function_2
# HTTP (for Node/Python servers running on the runner)
mcp-servers:
my-node-tool:
type: http
url: "http://localhost:8765/mcp"
HTTP MCP servers are also supported with optional upstream authentication:
mcp-servers:
my-server:
type: http
url: "https://myserver.example.com/mcp"
headers:
Authorization: "Bearer ${{ secrets.API_KEY }}" # Optional: custom headers
my-oidc-server:
type: http
url: "https://myserver.example.com/mcp"
auth:
type: github-oidc # GitHub Actions OIDC token authentication
audience: "https://myserver.example.com" # Optional: custom OIDC audience
auth.type: github-oidc uses GitHub Actions OIDC tokens for secure server-to-server authentication without static credentials. The audience field is optional and defaults to the server URL when omitted.
Engine Network Permissions
Control network access for AI engines using the top-level network: field. If no network: permission is specified, it defaults to network: defaults which provides access to basic infrastructure only.
engine:
id: copilot
# Basic infrastructure only (default)
network: defaults
# Use ecosystem identifiers for common development tools
network:
allowed:
- defaults # Basic infrastructure
- python # Python/PyPI ecosystem
- node # Node.js/NPM ecosystem
- containers # Container registries
- "api.custom.com" # Custom domain
- "https://secure.api.com" # Protocol-specific domain (HTTPS-only)
blocked:
- "tracking.com" # Block specific domains
- "*.ads.com" # Block domain patterns
- ruby # Block ecosystem identifiers
firewall: true # Enable AWF (Copilot engine only)
# Or allow specific domains only
network:
allowed:
- "api.github.com"
- "*.trusted-domain.com"
- "example.com"
# Or deny all network access
network: {}
Access Levels:
- Default Allow List (
network: defaults): Basic infrastructure only (certificates, JSON schema, Ubuntu mirrors, Microsoft sources).
- Selective Access (
network: { allowed: [...] }): Only listed domains/ecosystems are accessible. Listed domains automatically match all subdomains.
- No Access (
network: {}): All network access denied.
Wildcard Domain Patterns:
Use wildcard patterns (*.example.com) to match any subdomain. Wildcards match the base domain and all subdomains at any depth. Only a single leading wildcard is allowed (e.g., *.*.example.com is invalid). Both example.com and *.example.com match all subdomains; use the wildcard form to be explicit.
Protocol-Specific Domain Filtering:
Restrict domains to a specific protocol by prefixing with https:// or http://. Domains without a prefix allow both. Supported by Copilot and Claude engines with AWF enabled.
Content Sanitization:
Domains not in the allowed list are replaced with (redacted) in sanitized content to prevent data exfiltration. GitHub domains are always allowed by default.
Ecosystem Identifier Validation:
Single-word entries matching the ecosystem pattern are validated against the known list at compile time. Unrecognized identifiers produce a compilation error.
Strict Mode Validation:
When strict: true (default), the compiler warns when individual ecosystem domains (e.g., pypi.org, npmjs.org) are used, recommending ecosystem identifiers (python, node) instead.
Implementation Details:
- Firewall (AWF): The Copilot engine supports network permissions through AWF (Agent Workflow Firewall). Enable with
firewall: true.
- Log Level: Control AWF verbosity with
log-level: info (options: debug, info, warn, error).
- SSL Bump: Enable with
ssl-bump: true to inspect HTTPS traffic and filter by URL paths using allow-urls.
- Effective Token Steering: AWF injects budget warnings at 80%, 90%, 95%, and 99% of
max-effective-tokens. Set to -1 to disable enforcement.
- Disabling Firewall: The firewall defaults to enabled (
sandbox.agent: awf). If disabled, permissions still apply for sanitization but the agent has unrestricted network requests.
Troubleshooting:
- Use
gh aw logs --run-id <run-id> to identify blocked domains.
- Use
gh aw audit <run-id> for detailed firewall analysis and policy attribution.
Important Notes:
- Network permissions apply to AI engines' WebFetch and WebSearch tools
- Uses top-level
network: field (not nested under engine permissions)
defaults now includes only basic infrastructure (certificates, JSON schema, Ubuntu, etc.)
- Use ecosystem identifiers (
python, node, java, etc.) for language-specific tools
- When custom permissions are specified with
allowed: list, deny-by-default policy is enforced
- Supports exact domain matches and wildcard patterns (where
* matches any characters, including nested subdomains)
- Protocol-specific filtering: Prefix domains with
http:// or https:// for protocol restrictions
- Domain blocklist: Use
blocked: field to explicitly deny domains or ecosystem identifiers
- Firewall support: Copilot engine supports AWF (Agent Workflow Firewall) for domain-based access control
- Claude engine uses hooks for enforcement; Codex support planned
Permission Modes:
- Basic infrastructure:
network: defaults or no network: field (certificates, JSON schema, Ubuntu only)
- Ecosystem access:
network: { allowed: [defaults, python, node, ...] } (development tool ecosystems)
- No network access:
network: {} (deny all)
- Specific domains:
network: { allowed: ["api.example.com", ...] } (granular access control)
- Block specific domains:
network: { blocked: ["tracking.com", "*.ads.com", ...] } (deny-list)
Available Ecosystem Identifiers:
Each ecosystem identifier enables network access to the domains required by that language's package manager and toolchain. When writing workflows that involve package management, builds, or tests, always include the ecosystem identifier matching the repository's primary language in addition to defaults.
| Identifier | Runtimes / Languages | Package Manager / Domains |
|---|
defaults | All (always include) | Certificates, JSON schema, Ubuntu mirrors, Microsoft sources |
github | Any | GitHub domains (github.com, api.github.com, docs.github.com, github.blog, *.githubusercontent.com, and related) |
local | Any | Loopback addresses (localhost, 127.0.0.1, ::1) |
dev-tools | Any | Popular CI/CD and developer tool services (Codecov, Shields.io, Snyk, Renovate, CircleCI, etc.) |
default-safe-outputs | Any | Compound: defaults + dev-tools + github + local — recommended baseline for safe-outputs.allowed-domains |
containers | Docker, OCI | Docker Hub, GitHub Container Registry, Quay (registry.hub.docker.com, ghcr.io, etc.) |
linux-distros | Any | Debian, Alpine, and other Linux package repositories (apt, yum/dnf mirrors) |
dotnet | C#, F#, VB.NET | NuGet (nuget.org, api.nuget.org, dotnetcli.blob.core.windows.net, etc.) |
python | Python | pip, conda, PyPI (pypi.org, files.pythonhosted.org, conda.anaconda.org, etc.) |
node | Node.js, JS, TS | npm, yarn, pnpm (registry.npmjs.org, yarnpkg.com, etc.) |
deno | Deno | Deno runtime (deno.land, jsr.io, , , ) |
Network Inference Rule: When a workflow will run dotnet restore, pip install, npm install, go mod download, mvn install, etc., infer the ecosystem from the repository language and include it. Examples:
.NET repository (.csproj, .fsproj, *.sln, *.slnx) → network: { allowed: [defaults, dotnet] }
- Python repository (
requirements.txt, pyproject.toml) → network: { allowed: [defaults, python] }
- Node.js repository (
package.json) → network: { allowed: [defaults, node] }
- Go repository (
go.mod) → network: { allowed: [defaults, go] }
- Java repository (
pom.xml, build.gradle) → network: { allowed: [defaults, java] }
Imports Field
Import shared components or Copilot custom agent files using the imports: field in frontmatter:
---
on: issues
engine: copilot
imports:
- copilot-setup-steps.yml # Import setup steps from copilot-setup-steps.yml
- shared/security-notice.md
- shared/tool-setup.md
- shared/mcp/tavily.md
- .github/agents/my-agent.md # Local Copilot custom agent file
- acme-org/shared-agents/.github/agents/code-reviewer.md@v1.0.0 # Remote Copilot custom agent file
---
Copilot Custom Agents:
- Markdown files stored in the
.github/agents/ directory (local or remote repository).
- Only one agent file can be imported per workflow.
- Alternatively, you can define sub-agents inline using a
## agent: \name`` heading inside the workflow markdown file.
Object form with inputs — Use path:/uses: + with:/inputs: to pass values to shared workflows that define an import-schema:. Optional checkout: and env: fields customize the import:
imports:
- path: shared/tool-setup.md
with:
environment: staging
max-issues: 3
env:
MY_VAR: "value" # Optional: pass env vars into the imported workflow
checkout: main # Optional: ref to check out when this import is processed
- uses: shared/security-notice.md # 'uses' is an alias for 'path'
env: - Environment variables passed into the imported workflow context (object). Use when a shared workflow relies on environment variables that must be supplied by the importing workflow.
checkout: - Ref (branch, tag, or SHA) to check out when processing this import (string). Overrides the default checkout for this specific import entry.
Inside the imported workflow, access values via ${{ github.aw.import-inputs.<name> }}.
Import File Structure
Import files are in .github/workflows/shared/ and can contain:
- Tool configurations
- Safe-outputs configurations
- Text content
- Mixed frontmatter + content
The following frontmatter fields in imported files are merged into the importing workflow:
tools: - Merged with the importing workflow's tools
safe-outputs: - Merged with safe-output configuration
env: - Environment variables merged; conflicts between two imports defining the same key are compilation errors (remove the duplicate or move it to the main workflow to override)
checkout: - Checkout configurations appended (main workflow's checkouts take precedence)
github-app: - Top-level GitHub App credentials (first-wins across imports)
on.github-app: - Activation GitHub App credentials (first-wins across imports)
steps:, pre-steps:, pre-agent-steps:, post-steps: - Steps appended in import order
runtimes:, network:, permissions:, services:, cache:, features:, mcp-servers:
Example import file:
---
tools:
github:
allowed: [get_repository, list_commits]
safe-outputs:
create-issue:
labels: [automation]
env:
MY_VAR: "shared-value"
checkout:
fetch-depth: 0
---
Additional instructions for the coding agent.
Special Import: copilot-setup-steps.yml
The copilot-setup-steps.yml file receives special handling when imported. Instead of importing the entire job structure, only the steps from the copilot-setup-steps job are extracted and inserted at the start of your workflow's agent job.
Key behaviors:
- Only the steps array is imported (job metadata like
runs-on, permissions is ignored)
- Imported steps are placed at the start of the agent job (before all other steps)
- Other imported steps are placed after copilot-setup-steps but before main frontmatter steps
- Main frontmatter steps come last
- Final order: copilot-setup-steps → other imported steps → main frontmatter steps
- Supports both
.yml and .yaml extensions
- Enables clean reuse of common setup configurations across workflows
Example:
---
on: issue_comment
engine: copilot
imports:
- copilot-setup-steps.yml
- shared/common-tools.md
steps:
- name: Custom environment setup
run: echo "Main frontmatter step runs last"
---
In the compiled workflow, the order is: copilot-setup-steps → imported steps from shared/common-tools.md → main frontmatter steps.
Permission Patterns
IMPORTANT: Agentic workflows should NOT include write permissions (issues: write, pull-requests: write, contents: write). The safe-outputs system provides these capabilities through separate, secured jobs with appropriate permissions. NO write permissions should be granted to the main AI processing job, it will only cause a later compilation error.
Read-Only Pattern
permissions:
contents: read
metadata: read
Output Processing Pattern (Recommended)
permissions:
contents: read # Main job minimal permissions
actions: read
safe-outputs:
create-issue: # Automatic issue creation
add-comment: # Automatic comment creation
create-pull-request: # Automatic PR creation
Key Benefits of Safe-Outputs:
- Security: Main job runs with minimal permissions
- Separation of Concerns: Write operations are handled by dedicated jobs
- Permission Management: Safe-outputs jobs automatically receive required permissions
- Audit Trail: Clear separation between AI processing and GitHub API interactions
References