diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index af3ee6c542..b91118c91b 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -5,25 +5,36 @@ "description": "JSON Schema for validating agentic workflow frontmatter configuration", "version": "1.0.0", "type": "object", - "required": ["on"], + "required": [ + "on" + ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 256, "description": "Workflow name that appears in the GitHub Actions interface. If not specified, defaults to the filename without extension.", - "examples": ["Copilot Agent PR Analysis", "Dev Hawk", "Smoke Claude"] + "examples": [ + "Copilot Agent PR Analysis", + "Dev Hawk", + "Smoke Claude" + ] }, "description": { "type": "string", "maxLength": 10000, "description": "Optional workflow description that is rendered as a comment in the generated GitHub Actions YAML file (.lock.yml)", - "examples": ["Quickstart for using the GitHub Actions library"] + "examples": [ + "Quickstart for using the GitHub Actions library" + ] }, "source": { "type": "string", "description": "Optional source reference indicating where this workflow was added from. Format: owner/repo/path@ref (e.g., githubnext/agentics/workflows/ci-doctor.md@v1.0.0). Rendered as a comment in the generated lock file.", - "examples": ["githubnext/agentics/workflows/ci-doctor.md", "githubnext/agentics/workflows/daily-perf-improver.md@1f181b37d3fe5862ab590648f25a292e345b5de6"] + "examples": [ + "githubnext/agentics/workflows/ci-doctor.md", + "githubnext/agentics/workflows/daily-perf-improver.md@1f181b37d3fe5862ab590648f25a292e345b5de6" + ] }, "tracker-id": { "type": "string", @@ -31,7 +42,11 @@ "maxLength": 128, "pattern": "^[a-zA-Z0-9_-]+$", "description": "Optional tracker identifier to tag all created assets (issues, discussions, comments, pull requests). Must be at least 8 characters and contain only alphanumeric characters, hyphens, and underscores. This identifier will be inserted in the body/description of all created assets to enable searching and retrieving assets associated with this workflow.", - "examples": ["workflow-2024-q1", "team-alpha-bot", "security_audit_v2"] + "examples": [ + "workflow-2024-q1", + "team-alpha-bot", + "security_audit_v2" + ] }, "labels": { "type": "array", @@ -41,9 +56,18 @@ "minLength": 1 }, "examples": [ - ["automation", "security"], - ["docs", "maintenance"], - ["ci", "testing"] + [ + "automation", + "security" + ], + [ + "docs", + "maintenance" + ], + [ + "ci", + "testing" + ] ] }, "metadata": { @@ -77,7 +101,9 @@ { "type": "object", "description": "Import specification with path and optional inputs", - "required": ["path"], + "required": [ + "path" + ], "additionalProperties": false, "properties": { "path": { @@ -106,10 +132,21 @@ ] }, "examples": [ - ["shared/jqschema.md", "shared/reporting.md"], - ["shared/mcp/gh-aw.md", "shared/jqschema.md", "shared/reporting.md"], - ["../instructions/documentation.instructions.md"], - [".github/agents/my-agent.md"], + [ + "shared/jqschema.md", + "shared/reporting.md" + ], + [ + "shared/mcp/gh-aw.md", + "shared/jqschema.md", + "shared/reporting.md" + ], + [ + "../instructions/documentation.instructions.md" + ], + [ + ".github/agents/my-agent.md" + ], [ { "path": "shared/discussions-data-fetch.md", @@ -125,12 +162,17 @@ "examples": [ { "issues": { - "types": ["opened"] + "types": [ + "opened" + ] } }, { "pull_request": { - "types": ["opened", "synchronize"] + "types": [ + "opened", + "synchronize" + ] } }, "workflow_dispatch", @@ -144,7 +186,13 @@ "type": "string", "minLength": 1, "description": "Simple trigger event name (e.g., 'push', 'issues', 'pull_request', 'discussion', 'schedule', 'fork', 'create', 'delete', 'public', 'watch', 'workflow_call'), schedule shorthand (e.g., 'daily', 'weekly'), or slash command shorthand (e.g., '/my-bot' expands to slash_command + workflow_dispatch)", - "examples": ["push", "issues", "workflow_dispatch", "daily", "/my-bot"] + "examples": [ + "push", + "issues", + "workflow_dispatch", + "daily", + "/my-bot" + ] }, { "type": "object", @@ -196,7 +244,16 @@ { "type": "string", "description": "Single event name or '*' for all events. Use GitHub Actions event names: 'issues', 'issue_comment', 'pull_request_comment', 'pull_request', 'pull_request_review_comment', 'discussion', 'discussion_comment'.", - "enum": ["*", "issues", "issue_comment", "pull_request_comment", "pull_request", "pull_request_review_comment", "discussion", "discussion_comment"] + "enum": [ + "*", + "issues", + "issue_comment", + "pull_request_comment", + "pull_request", + "pull_request_review_comment", + "discussion", + "discussion_comment" + ] }, { "type": "array", @@ -205,7 +262,16 @@ "items": { "type": "string", "description": "GitHub Actions event name.", - "enum": ["*", "issues", "issue_comment", "pull_request_comment", "pull_request", "pull_request_review_comment", "discussion", "discussion_comment"] + "enum": [ + "*", + "issues", + "issue_comment", + "pull_request_comment", + "pull_request", + "pull_request_review_comment", + "discussion", + "discussion_comment" + ] }, "maxItems": 25 } @@ -262,7 +328,16 @@ { "type": "string", "description": "Single event name or '*' for all events. Use GitHub Actions event names: 'issues', 'issue_comment', 'pull_request_comment', 'pull_request', 'pull_request_review_comment', 'discussion', 'discussion_comment'.", - "enum": ["*", "issues", "issue_comment", "pull_request_comment", "pull_request", "pull_request_review_comment", "discussion", "discussion_comment"] + "enum": [ + "*", + "issues", + "issue_comment", + "pull_request_comment", + "pull_request", + "pull_request_review_comment", + "discussion", + "discussion_comment" + ] }, { "type": "array", @@ -271,7 +346,16 @@ "items": { "type": "string", "description": "GitHub Actions event name.", - "enum": ["*", "issues", "issue_comment", "pull_request_comment", "pull_request", "pull_request_review_comment", "discussion", "discussion_comment"] + "enum": [ + "*", + "issues", + "issue_comment", + "pull_request_comment", + "pull_request", + "pull_request_review_comment", + "discussion", + "discussion_comment" + ] }, "maxItems": 25 } @@ -336,25 +420,37 @@ }, "oneOf": [ { - "required": ["branches"], + "required": [ + "branches" + ], "not": { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } }, { - "required": ["branches-ignore"], + "required": [ + "branches-ignore" + ], "not": { - "required": ["branches"] + "required": [ + "branches" + ] } }, { "not": { "anyOf": [ { - "required": ["branches"] + "required": [ + "branches" + ] }, { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } ] } @@ -364,25 +460,37 @@ { "oneOf": [ { - "required": ["paths"], + "required": [ + "paths" + ], "not": { - "required": ["paths-ignore"] + "required": [ + "paths-ignore" + ] } }, { - "required": ["paths-ignore"], + "required": [ + "paths-ignore" + ], "not": { - "required": ["paths"] + "required": [ + "paths" + ] } }, { "not": { "anyOf": [ { - "required": ["paths"] + "required": [ + "paths" + ] }, { - "required": ["paths-ignore"] + "required": [ + "paths-ignore" + ] } ] } @@ -502,25 +610,37 @@ "additionalProperties": false, "oneOf": [ { - "required": ["branches"], + "required": [ + "branches" + ], "not": { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } }, { - "required": ["branches-ignore"], + "required": [ + "branches-ignore" + ], "not": { - "required": ["branches"] + "required": [ + "branches" + ] } }, { "not": { "anyOf": [ { - "required": ["branches"] + "required": [ + "branches" + ] }, { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } ] } @@ -530,25 +650,37 @@ { "oneOf": [ { - "required": ["paths"], + "required": [ + "paths" + ], "not": { - "required": ["paths-ignore"] + "required": [ + "paths-ignore" + ] } }, { - "required": ["paths-ignore"], + "required": [ + "paths-ignore" + ], "not": { - "required": ["paths"] + "required": [ + "paths" + ] } }, { "not": { "anyOf": [ { - "required": ["paths"] + "required": [ + "paths" + ] }, { - "required": ["paths-ignore"] + "required": [ + "paths-ignore" + ] } ] } @@ -567,7 +699,26 @@ "description": "Types of issue events", "items": { "type": "string", - "enum": ["opened", "edited", "deleted", "transferred", "pinned", "unpinned", "closed", "reopened", "assigned", "unassigned", "labeled", "unlabeled", "locked", "unlocked", "milestoned", "demilestoned", "typed", "untyped"] + "enum": [ + "opened", + "edited", + "deleted", + "transferred", + "pinned", + "unpinned", + "closed", + "reopened", + "assigned", + "unassigned", + "labeled", + "unlabeled", + "locked", + "unlocked", + "milestoned", + "demilestoned", + "typed", + "untyped" + ] } }, "names": { @@ -605,7 +756,11 @@ "description": "Types of issue comment events", "items": { "type": "string", - "enum": ["created", "edited", "deleted"] + "enum": [ + "created", + "edited", + "deleted" + ] } }, "lock-for-agent": { @@ -624,7 +779,21 @@ "description": "Types of discussion events", "items": { "type": "string", - "enum": ["created", "edited", "deleted", "transferred", "pinned", "unpinned", "labeled", "unlabeled", "locked", "unlocked", "category_changed", "answered", "unanswered"] + "enum": [ + "created", + "edited", + "deleted", + "transferred", + "pinned", + "unpinned", + "labeled", + "unlabeled", + "locked", + "unlocked", + "category_changed", + "answered", + "unanswered" + ] } } } @@ -639,7 +808,11 @@ "description": "Types of discussion comment events", "items": { "type": "string", - "enum": ["created", "edited", "deleted"] + "enum": [ + "created", + "edited", + "deleted" + ] } } } @@ -664,7 +837,9 @@ "description": "Cron expression using standard format (e.g., '0 9 * * 1') or fuzzy format (e.g., 'daily', 'daily around 14:00', 'daily between 9:00 and 17:00', 'weekly', 'weekly on monday', 'weekly on friday around 5pm', 'hourly', 'every 2h', 'every 10 minutes'). Fuzzy formats support: daily/weekly schedules with optional time windows, hourly intervals with scattered minutes, interval schedules (minimum 5 minutes), short duration units (m/h/d/w), and UTC timezone offsets (utc+N or utc+HH:MM)." } }, - "required": ["cron"], + "required": [ + "cron" + ], "additionalProperties": false }, "maxItems": 10 @@ -714,7 +889,13 @@ }, "type": { "type": "string", - "enum": ["string", "choice", "boolean", "number", "environment"], + "enum": [ + "string", + "choice", + "boolean", + "number", + "environment" + ], "description": "Input type. GitHub Actions supports: string (default), boolean, choice (string with predefined options), number, and environment (string referencing a GitHub environment)" }, "options": { @@ -748,7 +929,11 @@ "description": "Types of workflow run events", "items": { "type": "string", - "enum": ["completed", "requested", "in_progress"] + "enum": [ + "completed", + "requested", + "in_progress" + ] } }, "branches": { @@ -770,25 +955,37 @@ }, "oneOf": [ { - "required": ["branches"], + "required": [ + "branches" + ], "not": { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } }, { - "required": ["branches-ignore"], + "required": [ + "branches-ignore" + ], "not": { - "required": ["branches"] + "required": [ + "branches" + ] } }, { "not": { "anyOf": [ { - "required": ["branches"] + "required": [ + "branches" + ] }, { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } ] } @@ -805,7 +1002,15 @@ "description": "Types of release events", "items": { "type": "string", - "enum": ["published", "unpublished", "created", "edited", "deleted", "prereleased", "released"] + "enum": [ + "published", + "unpublished", + "created", + "edited", + "deleted", + "prereleased", + "released" + ] } } } @@ -820,7 +1025,11 @@ "description": "Types of pull request review comment events", "items": { "type": "string", - "enum": ["created", "edited", "deleted"] + "enum": [ + "created", + "edited", + "deleted" + ] } } } @@ -835,7 +1044,11 @@ "description": "Types of branch protection rule events", "items": { "type": "string", - "enum": ["created", "edited", "deleted"] + "enum": [ + "created", + "edited", + "deleted" + ] } } } @@ -850,7 +1063,12 @@ "description": "Types of check run events", "items": { "type": "string", - "enum": ["created", "rerequested", "completed", "requested_action"] + "enum": [ + "created", + "rerequested", + "completed", + "requested_action" + ] } } } @@ -865,7 +1083,9 @@ "description": "Types of check suite events", "items": { "type": "string", - "enum": ["completed"] + "enum": [ + "completed" + ] } } } @@ -958,7 +1178,11 @@ "description": "Types of label events", "items": { "type": "string", - "enum": ["created", "edited", "deleted"] + "enum": [ + "created", + "edited", + "deleted" + ] } } } @@ -973,7 +1197,9 @@ "description": "Types of merge group events", "items": { "type": "string", - "enum": ["checks_requested"] + "enum": [ + "checks_requested" + ] } } } @@ -988,7 +1214,13 @@ "description": "Types of milestone events", "items": { "type": "string", - "enum": ["created", "closed", "opened", "edited", "deleted"] + "enum": [ + "created", + "closed", + "opened", + "edited", + "deleted" + ] } } } @@ -1106,25 +1338,37 @@ "additionalProperties": false, "oneOf": [ { - "required": ["branches"], + "required": [ + "branches" + ], "not": { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } }, { - "required": ["branches-ignore"], + "required": [ + "branches-ignore" + ], "not": { - "required": ["branches"] + "required": [ + "branches" + ] } }, { "not": { "anyOf": [ { - "required": ["branches"] + "required": [ + "branches" + ] }, { - "required": ["branches-ignore"] + "required": [ + "branches-ignore" + ] } ] } @@ -1134,25 +1378,37 @@ { "oneOf": [ { - "required": ["paths"], + "required": [ + "paths" + ], "not": { - "required": ["paths-ignore"] + "required": [ + "paths-ignore" + ] } }, { - "required": ["paths-ignore"], + "required": [ + "paths-ignore" + ], "not": { - "required": ["paths"] + "required": [ + "paths" + ] } }, { "not": { "anyOf": [ { - "required": ["paths"] + "required": [ + "paths" + ] }, { - "required": ["paths-ignore"] + "required": [ + "paths-ignore" + ] } ] } @@ -1171,7 +1427,11 @@ "description": "Types of pull request review events", "items": { "type": "string", - "enum": ["submitted", "edited", "dismissed"] + "enum": [ + "submitted", + "edited", + "dismissed" + ] } } } @@ -1186,7 +1446,10 @@ "description": "Types of registry package events", "items": { "type": "string", - "enum": ["published", "updated"] + "enum": [ + "published", + "updated" + ] } } } @@ -1228,7 +1491,9 @@ "description": "Types of watch events", "items": { "type": "string", - "enum": ["started"] + "enum": [ + "started" + ] } } } @@ -1260,7 +1525,11 @@ }, "type": { "type": "string", - "enum": ["string", "number", "boolean"], + "enum": [ + "string", + "number", + "boolean" + ], "description": "Type of the input parameter" }, "default": { @@ -1302,7 +1571,9 @@ }, { "type": "object", - "required": ["query"], + "required": [ + "query" + ], "properties": { "query": { "type": "string", @@ -1328,7 +1599,9 @@ }, { "type": "object", - "required": ["query"], + "required": [ + "query" + ], "properties": { "query": { "type": "string", @@ -1385,7 +1658,9 @@ "oneOf": [ { "type": "string", - "enum": ["all"], + "enum": [ + "all" + ], "description": "Allow any authenticated user to trigger the workflow (⚠️ disables permission checking entirely - use with caution)" }, { @@ -1393,7 +1668,13 @@ "description": "List of repository permission levels that can trigger the workflow. Permission checks are automatically applied to potentially unsafe triggers.", "items": { "type": "string", - "enum": ["admin", "maintainer", "maintain", "write", "triage"], + "enum": [ + "admin", + "maintainer", + "maintain", + "write", + "triage" + ], "description": "Repository permission level: 'admin' (full access), 'maintainer'/'maintain' (repository management), 'write' (push access), 'triage' (issue management)" }, "minItems": 1, @@ -1409,22 +1690,45 @@ "oneOf": [ { "type": "string", - "enum": ["+1", "-1", "laugh", "confused", "heart", "hooray", "rocket", "eyes", "none"] + "enum": [ + "+1", + "-1", + "laugh", + "confused", + "heart", + "hooray", + "rocket", + "eyes", + "none" + ] }, { "type": "integer", - "enum": [1, -1], + "enum": [ + 1, + -1 + ], "description": "YAML parses +1 and -1 without quotes as integers. These are converted to +1 and -1 strings respectively." } ], "default": "eyes", "description": "AI reaction to add/remove on triggering item (one of: +1, -1, laugh, confused, heart, hooray, rocket, eyes, none). Use 'none' to disable reactions. Defaults to 'eyes' if not specified.", - "examples": ["eyes", "rocket", "+1", 1, -1, "none"] + "examples": [ + "eyes", + "rocket", + "+1", + 1, + -1, + "none" + ] }, "status-comment": { "type": "boolean", "description": "Whether to post status comments (started/completed) on the triggering item. When true, adds a comment with workflow run link and updates it on completion. When false or not specified, no status comments are posted. Must be explicitly set to true to enable status comments - there is no automatic bundling with ai-reaction.", - "examples": [true, false] + "examples": [ + true, + false + ] } }, "additionalProperties": false, @@ -1440,25 +1744,37 @@ { "command": { "name": "mergefest", - "events": ["pull_request_comment"] + "events": [ + "pull_request_comment" + ] } }, { "workflow_run": { - "workflows": ["Dev"], - "types": ["completed"], - "branches": ["copilot/**"] + "workflows": [ + "Dev" + ], + "types": [ + "completed" + ], + "branches": [ + "copilot/**" + ] } }, { "pull_request": { - "types": ["ready_for_review"] + "types": [ + "ready_for_review" + ] }, "workflow_dispatch": null }, { "push": { - "branches": ["main"] + "branches": [ + "main" + ] } } ] @@ -1485,7 +1801,10 @@ "oneOf": [ { "type": "string", - "enum": ["read-all", "write-all"], + "enum": [ + "read-all", + "write-all" + ], "description": "Simple permissions string: 'read-all' (all read permissions) or 'write-all' (all write permissions)" }, { @@ -1495,82 +1814,143 @@ "properties": { "actions": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for GitHub Actions workflows and runs (read: view workflows, write: manage workflows, none: no access)" }, "attestations": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for artifact attestations (read: view attestations, write: create attestations, none: no access)" }, "checks": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for repository checks and status checks (read: view checks, write: create/update checks, none: no access)" }, "contents": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for repository contents (read: view files, write: modify files/branches, none: no access)" }, "deployments": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for repository deployments (read: view deployments, write: create/update deployments, none: no access)" }, "discussions": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for repository discussions (read: view discussions, write: create/update discussions, none: no access)" }, "id-token": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission level for OIDC token requests (read/write/none). Allows workflows to request JWT tokens for cloud provider authentication." }, "issues": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for repository issues (read: view issues, write: create/update/close issues, none: no access)" }, "models": { "type": "string", - "enum": ["read", "none"], + "enum": [ + "read", + "none" + ], "description": "Permission for GitHub Copilot models (read: access AI models for agentic workflows, none: no access)" }, "metadata": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission for repository metadata (read: view repository information, write: update repository metadata, none: no access)" }, "packages": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission level for GitHub Packages (read/write/none). Controls access to publish, modify, or delete packages." }, "pages": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission level for GitHub Pages (read/write/none). Controls access to deploy and manage GitHub Pages sites." }, "pull-requests": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission level for pull requests (read/write/none). Controls access to create, edit, review, and manage pull requests." }, "security-events": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission level for security events (read/write/none). Controls access to view and manage code scanning alerts and security findings." }, "statuses": { "type": "string", - "enum": ["read", "write", "none"], + "enum": [ + "read", + "write", + "none" + ], "description": "Permission level for commit statuses (read/write/none). Controls access to create and update commit status checks." }, "all": { "type": "string", - "enum": ["read"], + "enum": [ + "read" + ], "description": "Permission shorthand that applies read access to all permission scopes. Can be combined with specific write permissions to override individual scopes. 'write' is not allowed for all." } } @@ -1580,7 +1960,10 @@ "run-name": { "type": "string", "description": "Custom name for workflow runs that appears in the GitHub Actions interface (supports GitHub expressions like ${{ github.event.issue.title }})", - "examples": ["Deploy to ${{ github.event.inputs.environment }}", "Build #${{ github.run_number }}"] + "examples": [ + "Deploy to ${{ github.event.inputs.environment }}", + "Build #${{ github.run_number }}" + ] }, "jobs": { "type": "object", @@ -1623,10 +2006,14 @@ "additionalProperties": false, "oneOf": [ { - "required": ["uses"] + "required": [ + "uses" + ] }, { - "required": ["run"] + "required": [ + "run" + ] } ], "properties": { @@ -1839,17 +2226,26 @@ ], "examples": [ "ubuntu-latest", - ["ubuntu-latest", "self-hosted"], + [ + "ubuntu-latest", + "self-hosted" + ], { "group": "larger-runners", - "labels": ["ubuntu-latest-8-cores"] + "labels": [ + "ubuntu-latest-8-cores" + ] } ] }, "timeout-minutes": { "type": "integer", "description": "Workflow timeout in minutes (GitHub Actions standard field). Defaults to 20 minutes for agentic workflows. Has sensible defaults and can typically be omitted.", - "examples": [5, 10, 30] + "examples": [ + 5, + 10, + 30 + ] }, "concurrency": { "description": "Concurrency control to limit concurrent workflow runs (GitHub Actions standard field). Supports two forms: simple string for basic group isolation, or object with cancel-in-progress option for advanced control. Agentic workflows enhance this with automatic per-engine concurrency policies (defaults to single job per engine across all workflows) and token-based rate limiting. Default behavior: workflows in the same group queue sequentially unless cancel-in-progress is true. See https://docs.github.com/en/actions/using-jobs/using-concurrency", @@ -1857,7 +2253,10 @@ { "type": "string", "description": "Simple concurrency group name to prevent multiple runs in the same group. Use expressions like '${{ github.workflow }}' for per-workflow isolation or '${{ github.ref }}' for per-branch isolation. Agentic workflows automatically generate enhanced concurrency policies using 'gh-aw-{engine-id}' as the default group to limit concurrent AI workloads across all workflows using the same engine.", - "examples": ["my-workflow-group", "workflow-${{ github.ref }}"] + "examples": [ + "my-workflow-group", + "workflow-${{ github.ref }}" + ] }, { "type": "object", @@ -1873,7 +2272,9 @@ "description": "Whether to cancel in-progress workflows in the same concurrency group when a new one starts. Default: false (queue new runs). Set to true for agentic workflows where only the latest run matters (e.g., PR analysis that becomes stale when new commits are pushed)." } }, - "required": ["group"], + "required": [ + "group" + ], "examples": [ { "group": "dev-workflow-${{ github.ref }}", @@ -1933,12 +2334,16 @@ "infer": { "type": "boolean", "description": "DEPRECATED: Use 'disable-model-invocation' instead. Controls whether the custom agent should infer additional context from the conversation. This field is maintained for backward compatibility with existing custom agent files.", - "examples": [false] + "examples": [ + false + ] }, "disable-model-invocation": { "type": "boolean", "description": "Controls whether the custom agent should disable model invocation. When set to true, the agent will not make additional model calls. This is the preferred field name for custom agent files (replaces the deprecated 'infer' field).", - "examples": [true] + "examples": [ + true + ] }, "secrets": { "description": "Secret values passed to workflow execution. Secrets can be defined as simple strings (GitHub Actions expressions) or objects with 'value' and 'description' properties. Typically used to provide secrets to MCP servers or custom engines. Note: For passing secrets to reusable workflows, use the jobs..secrets field instead.", @@ -1952,7 +2357,9 @@ { "type": "object", "description": "Secret with metadata", - "required": ["value"], + "required": [ + "value" + ], "properties": { "value": { "type": "string", @@ -2004,7 +2411,9 @@ "description": "A deployment URL" } }, - "required": ["name"], + "required": [ + "name" + ], "additionalProperties": false } ] @@ -2072,7 +2481,9 @@ "description": "Additional Docker container options" } }, - "required": ["image"], + "required": [ + "image" + ], "additionalProperties": false } ] @@ -2142,7 +2553,9 @@ "description": "Additional Docker container options" } }, - "required": ["image"], + "required": [ + "image" + ], "additionalProperties": false } ] @@ -2154,13 +2567,24 @@ "examples": [ "defaults", { - "allowed": ["defaults", "github"] + "allowed": [ + "defaults", + "github" + ] }, { - "allowed": ["defaults", "python", "node", "*.example.com"] + "allowed": [ + "defaults", + "python", + "node", + "*.example.com" + ] }, { - "allowed": ["api.openai.com", "*.github.com"], + "allowed": [ + "api.openai.com", + "*.github.com" + ], "firewall": { "version": "v1.0.0", "log-level": "debug" @@ -2170,7 +2594,9 @@ "oneOf": [ { "type": "string", - "enum": ["defaults"], + "enum": [ + "defaults" + ], "description": "Use default network permissions (basic infrastructure: certificates, JSON schema, Ubuntu, etc.)" }, { @@ -2210,7 +2636,9 @@ }, { "type": "string", - "enum": ["disable"], + "enum": [ + "disable" + ], "description": "Disable AWF firewall (triggers warning if allowed != *, error in strict mode if allowed is not * or engine does not support firewall)" }, { @@ -2225,14 +2653,27 @@ } }, "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "AWF version to use (empty = latest release). Can be a string (e.g., 'v1.0.0', 'latest') or number (e.g., 20, 3.11). Numeric values are automatically converted to strings at runtime.", - "examples": ["v1.0.0", "latest", 20, 3.11] + "examples": [ + "v1.0.0", + "latest", + 20, + 3.11 + ] }, "log-level": { "type": "string", "description": "AWF log level (default: info). Valid values: debug, info, warn, error", - "enum": ["debug", "info", "warn", "error"] + "enum": [ + "debug", + "info", + "warn", + "error" + ] }, "ssl-bump": { "type": "boolean", @@ -2247,7 +2688,12 @@ "pattern": "^https://.*", "description": "HTTPS URL pattern with optional wildcards (e.g., 'https://github.com/githubnext/*')" }, - "examples": [["https://github.com/githubnext/*", "https://api.github.com/repos/*"]] + "examples": [ + [ + "https://github.com/githubnext/*", + "https://api.github.com/repos/*" + ] + ] } }, "additionalProperties": false @@ -2264,7 +2710,10 @@ "oneOf": [ { "type": "string", - "enum": ["default", "awf"], + "enum": [ + "default", + "awf" + ], "description": "String format for sandbox type: 'default' for no sandbox, 'awf' for Agent Workflow Firewall. Note: Legacy 'srt' and 'sandbox-runtime' values are automatically migrated to 'awf'" }, { @@ -2273,7 +2722,10 @@ "properties": { "type": { "type": "string", - "enum": ["default", "awf"], + "enum": [ + "default", + "awf" + ], "description": "Legacy sandbox type field (use agent instead). Note: Legacy 'srt' and 'sandbox-runtime' values are automatically migrated to 'awf'" }, "agent": { @@ -2287,7 +2739,9 @@ }, { "type": "string", - "enum": ["awf"], + "enum": [ + "awf" + ], "description": "Sandbox type: 'awf' for Agent Workflow Firewall" }, { @@ -2296,12 +2750,16 @@ "properties": { "id": { "type": "string", - "enum": ["awf"], + "enum": [ + "awf" + ], "description": "Agent identifier (replaces 'type' field in new format): 'awf' for Agent Workflow Firewall" }, "type": { "type": "string", - "enum": ["awf"], + "enum": [ + "awf" + ], "description": "Legacy: Sandbox type to use (use 'id' instead)" }, "command": { @@ -2330,7 +2788,12 @@ "pattern": "^[^:]+:[^:]+:(ro|rw)$", "description": "Mount specification in format 'source:destination:mode'" }, - "examples": [["/host/data:/data:ro", "/usr/local/bin/custom-tool:/usr/local/bin/custom-tool:ro"]] + "examples": [ + [ + "/host/data:/data:ro", + "/usr/local/bin/custom-tool:/usr/local/bin/custom-tool:ro" + ] + ] }, "config": { "type": "object", @@ -2445,14 +2908,24 @@ "description": "Container image for the MCP gateway executable (required)" }, "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional version/tag for the container image (e.g., 'latest', 'v1.0.0')", - "examples": ["latest", "v1.0.0"] + "examples": [ + "latest", + "v1.0.0" + ] }, "entrypoint": { "type": "string", "description": "Optional custom entrypoint for the MCP gateway container. Overrides the container's default entrypoint.", - "examples": ["/bin/bash", "/custom/start.sh", "/usr/bin/env"] + "examples": [ + "/bin/bash", + "/custom/start.sh", + "/usr/bin/env" + ] }, "args": { "type": "array", @@ -2476,7 +2949,12 @@ "pattern": "^[^:]+:[^:]+:(ro|rw)$", "description": "Mount specification in format 'source:destination:mode'" }, - "examples": [["/host/data:/container/data:ro", "/host/config:/container/config:rw"]] + "examples": [ + [ + "/host/data:/container/data:ro", + "/host/config:/container/config:rw" + ] + ] }, "env": { "type": "object", @@ -2501,11 +2979,16 @@ }, "domain": { "type": "string", - "enum": ["localhost", "host.docker.internal"], + "enum": [ + "localhost", + "host.docker.internal" + ], "description": "Gateway domain for URL generation (default: 'host.docker.internal' when agent is enabled, 'localhost' when disabled)" } }, - "required": ["container"], + "required": [ + "container" + ], "additionalProperties": false } }, @@ -2534,9 +3017,12 @@ ] }, "plugins": { - "description": "\u26a0\ufe0f EXPERIMENTAL: Plugin configuration for installing plugins before workflow execution. Supports array format (list of repos/plugin configs) and object format (repos + custom token). Note: Plugin support is experimental and may change in future releases.", + "description": "⚠️ EXPERIMENTAL: Plugin configuration for installing plugins before workflow execution. Supports array format (list of repos/plugin configs) and object format (repos + custom token). Note: Plugin support is experimental and may change in future releases.", "examples": [ - ["github/copilot-plugin", "acme/custom-tools"], + [ + "github/copilot-plugin", + "acme/custom-tools" + ], [ "github/simple-plugin", { @@ -2549,7 +3035,10 @@ } ], { - "repos": ["github/copilot-plugin", "acme/custom-tools"], + "repos": [ + "github/copilot-plugin", + "acme/custom-tools" + ], "github-token": "${{ secrets.CUSTOM_PLUGIN_TOKEN }}" } ], @@ -2567,7 +3056,9 @@ { "type": "object", "description": "Plugin configuration with ID and optional MCP settings for environment variables", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string", @@ -2603,7 +3094,9 @@ { "type": "object", "description": "Plugin configuration with custom GitHub token. Repos can be either strings or objects with MCP configuration.", - "required": ["repos"], + "required": [ + "repos" + ], "properties": { "repos": { "type": "array", @@ -2618,7 +3111,9 @@ { "type": "object", "description": "Plugin configuration with ID and optional MCP settings", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string", @@ -2648,7 +3143,9 @@ "github-token": { "type": "string", "description": "Custom GitHub token expression to use for plugin installation. Overrides the default cascading token resolution (GH_AW_PLUGINS_TOKEN -> GH_AW_GITHUB_TOKEN -> GITHUB_TOKEN).", - "examples": ["${{ secrets.CUSTOM_PLUGIN_TOKEN }}"] + "examples": [ + "${{ secrets.CUSTOM_PLUGIN_TOKEN }}" + ] } }, "additionalProperties": false @@ -2658,7 +3155,10 @@ "if": { "type": "string", "description": "Conditional execution expression", - "examples": ["${{ github.event.workflow_run.event == 'workflow_dispatch' }}", "${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}"] + "examples": [ + "${{ github.event.workflow_run.event == 'workflow_dispatch' }}", + "${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}" + ] }, "steps": { "description": "Custom workflow steps", @@ -2731,7 +3231,7 @@ [ { "name": "Verify Post-Steps Execution", - "run": "echo \"\u2705 Post-steps are executing correctly\"\necho \"This step runs after the AI agent completes\"\n" + "run": "echo \"✅ Post-steps are executing correctly\"\necho \"This step runs after the AI agent completes\"\n" }, { "name": "Upload Test Results", @@ -2776,7 +3276,10 @@ "filesystem": { "type": "stdio", "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-filesystem"] + "args": [ + "-y", + "@modelcontextprotocol/server-filesystem" + ] } }, { @@ -2853,13 +3356,24 @@ }, "mode": { "type": "string", - "enum": ["local", "remote"], + "enum": [ + "local", + "remote" + ], "description": "MCP server mode: 'local' (Docker-based, default) or 'remote' (hosted at api.githubcopilot.com)" }, "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional version specification for the GitHub MCP server (used with 'local' type). Can be a string (e.g., 'v1.0.0', 'latest') or number (e.g., 20, 3.11). Numeric values are automatically converted to strings at runtime.", - "examples": ["v1.0.0", "latest", 20, 3.11] + "examples": [ + "v1.0.0", + "latest", + 20, + 3.11 + ] }, "args": { "type": "array", @@ -2924,7 +3438,15 @@ "pattern": "^[^:]+:[^:]+(:(ro|rw))?$", "description": "Mount specification in format 'host:container:mode'" }, - "examples": [["/data:/data:ro", "/tmp:/tmp:rw"], ["/opt:/opt:ro"]] + "examples": [ + [ + "/data:/data:ro", + "/tmp:/tmp:rw" + ], + [ + "/opt:/opt:ro" + ] + ] }, "app": { "type": "object", @@ -2950,7 +3472,10 @@ } } }, - "required": ["app-id", "private-key"], + "required": [ + "app-id", + "private-key" + ], "additionalProperties": false, "examples": [ { @@ -2960,7 +3485,10 @@ { "app-id": "${{ vars.APP_ID }}", "private-key": "${{ secrets.APP_PRIVATE_KEY }}", - "repositories": ["repo1", "repo2"] + "repositories": [ + "repo1", + "repo2" + ] } ] } @@ -2968,16 +3496,30 @@ "additionalProperties": false, "examples": [ { - "toolsets": ["pull_requests", "actions", "repos"] + "toolsets": [ + "pull_requests", + "actions", + "repos" + ] }, { - "allowed": ["search_pull_requests", "pull_request_read", "list_pull_requests", "get_file_contents", "list_commits", "get_commit"] + "allowed": [ + "search_pull_requests", + "pull_request_read", + "list_pull_requests", + "get_file_contents", + "list_commits", + "get_commit" + ] }, { "read-only": true }, { - "toolsets": ["pull_requests", "repos"] + "toolsets": [ + "pull_requests", + "repos" + ] } ] } @@ -2985,14 +3527,25 @@ "examples": [ null, { - "toolsets": ["pull_requests", "actions", "repos"] + "toolsets": [ + "pull_requests", + "actions", + "repos" + ] }, { - "allowed": ["search_pull_requests", "pull_request_read", "get_file_contents"] + "allowed": [ + "search_pull_requests", + "pull_request_read", + "get_file_contents" + ] }, { "read-only": true, - "toolsets": ["repos", "issues"] + "toolsets": [ + "repos", + "issues" + ] }, false ] @@ -3019,10 +3572,36 @@ ], "examples": [ true, - ["git fetch", "git checkout", "git status", "git diff", "git log", "make recompile", "make fmt", "make lint", "make test-unit", "cat", "echo", "ls"], - ["echo", "ls", "cat"], - ["gh pr list *", "gh search prs *", "jq *"], - ["date *", "echo *", "cat", "ls"] + [ + "git fetch", + "git checkout", + "git status", + "git diff", + "git log", + "make recompile", + "make fmt", + "make lint", + "make test-unit", + "cat", + "echo", + "ls" + ], + [ + "echo", + "ls", + "cat" + ], + [ + "gh pr list *", + "gh search prs *", + "jq *" + ], + [ + "date *", + "echo *", + "cat", + "ls" + ] ] }, "web-fetch": { @@ -3099,9 +3678,16 @@ "description": "Playwright tool configuration with custom version and domain restrictions", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional Playwright container version (e.g., 'v1.41.0', 1.41, 20). Numeric values are automatically converted to strings at runtime.", - "examples": ["v1.41.0", 1.41, 20] + "examples": [ + "v1.41.0", + 1.41, + 20 + ] }, "allowed_domains": { "description": "Domains allowed for Playwright browser network access. Defaults to localhost only for security.", @@ -3143,7 +3729,10 @@ "description": "Enable agentic-workflows tool with default settings (same as true)" } ], - "examples": [true, null] + "examples": [ + true, + null + ] }, "cache-memory": { "description": "Cache memory MCP configuration for persistent memory storage", @@ -3180,7 +3769,10 @@ }, "scope": { "type": "string", - "enum": ["workflow", "repo"], + "enum": [ + "workflow", + "repo" + ], "default": "workflow", "description": "Cache restore key scope: 'workflow' (default, only restores from same workflow) or 'repo' (restores from any workflow in the repository). Use 'repo' with caution as it allows cross-workflow cache sharing." }, @@ -3233,7 +3825,10 @@ }, "scope": { "type": "string", - "enum": ["workflow", "repo"], + "enum": [ + "workflow", + "repo" + ], "default": "workflow", "description": "Cache restore key scope: 'workflow' (default, only restores from same workflow) or 'repo' (restores from any workflow in the repository). Use 'repo' with caution as it allows cross-workflow cache sharing." }, @@ -3245,7 +3840,10 @@ "description": "List of allowed file extensions (e.g., [\".json\", \".txt\"]). Default: [\".json\", \".jsonl\", \".txt\", \".md\", \".csv\"]" } }, - "required": ["id", "key"], + "required": [ + "id", + "key" + ], "additionalProperties": false }, "minItems": 1, @@ -3286,7 +3884,11 @@ "type": "integer", "minimum": 1, "description": "Timeout in seconds for tool/MCP server operations. Applies to all tools and MCP servers if supported by the engine. Default varies by engine (Claude: 60s, Codex: 120s).", - "examples": [60, 120, 300] + "examples": [ + 60, + 120, + 300 + ] }, "startup-timeout": { "type": "integer", @@ -3305,7 +3907,14 @@ "description": "Short syntax: array of language identifiers to enable (e.g., [\"go\", \"typescript\"])", "items": { "type": "string", - "enum": ["go", "typescript", "python", "java", "rust", "csharp"] + "enum": [ + "go", + "typescript", + "python", + "java", + "rust", + "csharp" + ] } }, { @@ -3313,14 +3922,24 @@ "description": "Serena configuration with custom version and language-specific settings", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional Serena MCP version. Numeric values are automatically converted to strings at runtime.", - "examples": ["latest", "0.1.0", 1.0] + "examples": [ + "latest", + "0.1.0", + 1.0 + ] }, "mode": { "type": "string", "description": "Serena execution mode: 'docker' (default, runs in container) or 'local' (runs locally with uvx and HTTP transport)", - "enum": ["docker", "local"], + "enum": [ + "docker", + "local" + ], "default": "docker" }, "args": { @@ -3344,7 +3963,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Go version (e.g., \"1.21\", 1.21)" }, "go-mod-file": { @@ -3371,7 +3993,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Node.js version for TypeScript (e.g., \"22\", 22)" } }, @@ -3390,7 +4015,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Python version (e.g., \"3.12\", 3.12)" } }, @@ -3409,7 +4037,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Java version (e.g., \"21\", 21)" } }, @@ -3428,7 +4059,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Rust version (e.g., \"stable\", \"1.75\")" } }, @@ -3447,7 +4081,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": ".NET version for C# (e.g., \"8.0\", 8.0)" } }, @@ -3693,11 +4330,19 @@ }, "type": { "type": "string", - "enum": ["stdio", "http", "remote", "local"], + "enum": [ + "stdio", + "http", + "remote", + "local" + ], "description": "MCP connection type. Use 'stdio' for command-based or container-based servers, 'http' for HTTP-based servers. 'local' is an alias for 'stdio' and is normalized during parsing." }, "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Version of the MCP server" }, "toolsets": { @@ -3734,7 +4379,10 @@ "registry": { "type": "string", "description": "URI to installation location from MCP registry", - "examples": ["https://api.mcp.github.com/v0/servers/microsoft/markitdown", "https://registry.npmjs.org/@my/tool"] + "examples": [ + "https://api.mcp.github.com/v0/servers/microsoft/markitdown", + "https://registry.npmjs.org/@my/tool" + ] }, "allowed": { "type": "array", @@ -3742,12 +4390,28 @@ "type": "string" }, "description": "List of allowed tool names (restricts which tools from the MCP server can be used)", - "examples": [["*"], ["store_memory", "retrieve_memory"], ["create-issue", "add-comment"]] + "examples": [ + [ + "*" + ], + [ + "store_memory", + "retrieve_memory" + ], + [ + "create-issue", + "add-comment" + ] + ] }, "entrypoint": { "type": "string", "description": "Optional entrypoint override for container (equivalent to docker run --entrypoint)", - "examples": ["/bin/sh", "/custom/entrypoint.sh", "python"] + "examples": [ + "/bin/sh", + "/custom/entrypoint.sh", + "python" + ] }, "mounts": { "type": "array", @@ -3756,7 +4420,15 @@ "pattern": "^[^:]+:[^:]+:(ro|rw)$" }, "description": "Volume mounts for container in format 'source:dest:mode' where mode is 'ro' or 'rw'", - "examples": [["/tmp/data:/data:ro"], ["/workspace:/workspace:rw", "/config:/config:ro"]] + "examples": [ + [ + "/tmp/data:/data:ro" + ], + [ + "/workspace:/workspace:rw", + "/config:/config:ro" + ] + ] } }, "additionalProperties": true @@ -3824,17 +4496,25 @@ "description": "If true, only checks if cache entry exists and skips download" } }, - "required": ["key", "path"], + "required": [ + "key", + "path" + ], "additionalProperties": false, "examples": [ { "key": "node-modules-${{ hashFiles('package-lock.json') }}", "path": "node_modules", - "restore-keys": ["node-modules-"] + "restore-keys": [ + "node-modules-" + ] }, { "key": "build-cache-${{ github.sha }}", - "path": ["dist", ".cache"], + "path": [ + "dist", + ".cache" + ], "restore-keys": "build-cache-", "fail-on-cache-miss": false } @@ -3895,7 +4575,10 @@ "description": "If true, only checks if cache entry exists and skips download" } }, - "required": ["key", "path"], + "required": [ + "key", + "path" + ], "additionalProperties": false } } @@ -3909,13 +4592,18 @@ { "create-issue": { "title-prefix": "[AI] ", - "labels": ["automation", "ai-generated"] + "labels": [ + "automation", + "ai-generated" + ] } }, { "create-pull-request": { "title-prefix": "[Bot] ", - "labels": ["bot"] + "labels": [ + "bot" + ] } }, { @@ -3938,7 +4626,19 @@ "type": "string", "pattern": "^(repo|[a-zA-Z0-9][-a-zA-Z0-9]{0,38}/[a-zA-Z0-9._-]+)$" }, - "examples": [["repo"], ["repo", "octocat/hello-world"], ["microsoft/vscode", "microsoft/typescript"]] + "examples": [ + [ + "repo" + ], + [ + "repo", + "octocat/hello-world" + ], + [ + "microsoft/vscode", + "microsoft/typescript" + ] + ] }, "create-issue": { "oneOf": [ @@ -4011,7 +4711,9 @@ }, { "type": "boolean", - "enum": [false], + "enum": [ + false + ], "description": "Set to false to explicitly disable expiration" } ], @@ -4037,21 +4739,33 @@ "examples": [ { "title-prefix": "[ca] ", - "labels": ["automation", "dependencies"], + "labels": [ + "automation", + "dependencies" + ], "assignees": "copilot" }, { "title-prefix": "[duplicate-code] ", - "labels": ["code-quality", "automated-analysis"], + "labels": [ + "code-quality", + "automated-analysis" + ], "assignees": "copilot" }, { - "allowed-repos": ["org/other-repo", "org/another-repo"], + "allowed-repos": [ + "org/other-repo", + "org/another-repo" + ], "title-prefix": "[cross-repo] " }, { "title-prefix": "[weekly-report] ", - "labels": ["report", "automation"], + "labels": [ + "report", + "automation" + ], "close-older-issues": true } ] @@ -4151,7 +4865,9 @@ { "type": "object", "description": "Configuration for managing GitHub Projects boards. Enable agents to add issues and pull requests to projects, update custom field values (status, priority, effort, dates), create project fields and views. By default it is update-only: if the project does not exist, the job fails with instructions to create it. To allow workflows to create missing projects, explicitly opt in via agent output field create_if_missing=true. Requires a Personal Access Token (PAT) or GitHub App token with Projects permissions (default GITHUB_TOKEN cannot be used). Agent output includes: project (full URL or temporary project ID like aw_XXXXXXXXXXXX or #aw_XXXXXXXXXXXX from create_project), content_type (issue|pull_request|draft_issue), content_number, fields, create_if_missing. For specialized operations, agent can also provide: operation (create_fields|create_view), field_definitions (array of field configs when operation=create_fields), view (view config object when operation=create_view).", - "required": ["project"], + "required": [ + "project" + ], "properties": { "max": { "type": "integer", @@ -4167,7 +4883,10 @@ "type": "string", "description": "Target project URL for update-project operations. This is required in the configuration for documentation purposes. Agent messages MUST explicitly include the project field in their output - the configured value is not used as a fallback. Must be a valid GitHub Projects v2 URL.", "pattern": "^https://github\\.com/(users|orgs)/([^/]+|<[A-Z_]+>)/projects/(\\d+|<[A-Z_]+>)$", - "examples": ["https://github.com/orgs/myorg/projects/123", "https://github.com/users/username/projects/456"] + "examples": [ + "https://github.com/orgs/myorg/projects/123", + "https://github.com/users/username/projects/456" + ] }, "views": { "type": "array", @@ -4175,7 +4894,10 @@ "items": { "type": "object", "description": "View configuration for creating project views", - "required": ["name", "layout"], + "required": [ + "name", + "layout" + ], "properties": { "name": { "type": "string", @@ -4183,7 +4905,11 @@ }, "layout": { "type": "string", - "enum": ["table", "board", "roadmap"], + "enum": [ + "table", + "board", + "roadmap" + ], "description": "The layout type of the view" }, "filter": { @@ -4210,7 +4936,10 @@ "description": "Optional array of project custom fields to create up-front.", "items": { "type": "object", - "required": ["name", "data-type"], + "required": [ + "name", + "data-type" + ], "properties": { "name": { "type": "string", @@ -4218,7 +4947,13 @@ }, "data-type": { "type": "string", - "enum": ["DATE", "TEXT", "NUMBER", "SINGLE_SELECT", "ITERATION"], + "enum": [ + "DATE", + "TEXT", + "NUMBER", + "SINGLE_SELECT", + "ITERATION" + ], "description": "The GitHub Projects v2 custom field type" }, "options": { @@ -4281,7 +5016,10 @@ "items": { "type": "object", "description": "View configuration for creating project views", - "required": ["name", "layout"], + "required": [ + "name", + "layout" + ], "properties": { "name": { "type": "string", @@ -4289,7 +5027,11 @@ }, "layout": { "type": "string", - "enum": ["table", "board", "roadmap"], + "enum": [ + "table", + "board", + "roadmap" + ], "description": "The layout type of the view" }, "filter": { @@ -4316,7 +5058,10 @@ "description": "Optional array of project custom fields to create automatically after project creation.", "items": { "type": "object", - "required": ["name", "data-type"], + "required": [ + "name", + "data-type" + ], "properties": { "name": { "type": "string", @@ -4324,7 +5069,13 @@ }, "data-type": { "type": "string", - "enum": ["DATE", "TEXT", "NUMBER", "SINGLE_SELECT", "ITERATION"], + "enum": [ + "DATE", + "TEXT", + "NUMBER", + "SINGLE_SELECT", + "ITERATION" + ], "description": "The GitHub Projects v2 custom field type" }, "options": { @@ -4346,7 +5097,9 @@ "description": "Enable project creation with default configuration (max=1)" }, { - "enum": [null], + "enum": [ + null + ], "description": "Alternative null value syntax" } ], @@ -4360,7 +5113,9 @@ { "type": "object", "description": "Configuration for posting status updates to GitHub Projects. Status updates provide stakeholder communication about project progress, health, and timeline. Each update appears in the project's Updates tab and creates a historical record. Requires a Personal Access Token (PAT) or GitHub App token with Projects read & write permission (default GITHUB_TOKEN cannot be used). Typically used by scheduled workflows or orchestrators to post regular progress summaries with status indicators (on-track, at-risk, off-track, complete, inactive), dates, and progress details.", - "required": ["project"], + "required": [ + "project" + ], "properties": { "max": { "type": "integer", @@ -4376,7 +5131,10 @@ "type": "string", "description": "Target project URL for status update operations. This is required in the configuration for documentation purposes. Agent messages MUST explicitly include the project field in their output - the configured value is not used as a fallback. Must be a valid GitHub Projects v2 URL.", "pattern": "^https://github\\.com/(users|orgs)/([^/]+|<[A-Z_]+>)/projects/(\\d+|<[A-Z_]+>)$", - "examples": ["https://github.com/orgs/myorg/projects/123", "https://github.com/users/username/projects/456"] + "examples": [ + "https://github.com/orgs/myorg/projects/123", + "https://github.com/users/username/projects/456" + ] } }, "additionalProperties": false, @@ -4408,9 +5166,16 @@ "description": "Optional prefix for the discussion title" }, "category": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional discussion category. Can be a category ID (string or numeric value), category name, or category slug/route. If not specified, uses the first available category. Matched first against category IDs, then against category names, then against category slugs. Numeric values are automatically converted to strings at runtime.", - "examples": ["General", "audits", 123456789] + "examples": [ + "General", + "audits", + 123456789 + ] }, "labels": { "type": "array", @@ -4472,7 +5237,9 @@ }, { "type": "boolean", - "enum": [false], + "enum": [ + false + ], "description": "Set to false to explicitly disable expiration" } ], @@ -4499,12 +5266,17 @@ "close-older-discussions": true }, { - "labels": ["weekly-report", "automation"], + "labels": [ + "weekly-report", + "automation" + ], "category": "reports", "close-older-discussions": true }, { - "allowed-repos": ["org/other-repo"], + "allowed-repos": [ + "org/other-repo" + ], "category": "General" } ] @@ -4558,7 +5330,10 @@ "required-category": "Ideas" }, { - "required-labels": ["resolved", "completed"], + "required-labels": [ + "resolved", + "completed" + ], "max": 1 } ] @@ -4669,7 +5444,10 @@ "required-title-prefix": "[refactor] " }, { - "required-labels": ["automated", "stale"], + "required-labels": [ + "automated", + "stale" + ], "max": 10 } ] @@ -4719,7 +5497,10 @@ "staged": { "type": "boolean", "description": "If true, emit step summary messages instead of making GitHub API calls for this specific output type (preview mode)", - "examples": [true, false] + "examples": [ + true, + false + ] } }, "additionalProperties": false, @@ -4728,7 +5509,10 @@ "required-title-prefix": "[bot] " }, { - "required-labels": ["automated", "outdated"], + "required-labels": [ + "automated", + "outdated" + ], "max": 5 } ] @@ -4782,7 +5566,10 @@ "required-title-prefix": "[bot] " }, { - "required-labels": ["automated", "ready"], + "required-labels": [ + "automated", + "ready" + ], "max": 1 } ] @@ -4836,7 +5623,13 @@ "description": "List of allowed reasons for hiding older comments when hide-older-comments is enabled. Default: all reasons allowed (spam, abuse, off_topic, outdated, resolved).", "items": { "type": "string", - "enum": ["spam", "abuse", "off_topic", "outdated", "resolved"] + "enum": [ + "spam", + "abuse", + "off_topic", + "outdated", + "resolved" + ] } }, "discussions": { @@ -4909,7 +5702,11 @@ }, "if-no-changes": { "type": "string", - "enum": ["warn", "error", "ignore"], + "enum": [ + "warn", + "error", + "ignore" + ], "description": "Behavior when no changes to push: 'warn' (default - log warning but succeed), 'error' (fail the action), or 'ignore' (silent success)" }, "allow-empty": { @@ -4970,13 +5767,19 @@ "examples": [ { "title-prefix": "[docs] ", - "labels": ["documentation", "automation"], + "labels": [ + "documentation", + "automation" + ], "reviewers": "copilot", "draft": false }, { "title-prefix": "[security-fix] ", - "labels": ["security", "automated-fix"], + "labels": [ + "security", + "automated-fix" + ], "reviewers": "copilot" } ] @@ -5003,7 +5806,10 @@ "side": { "type": "string", "description": "Side of the diff for comments: 'LEFT' or 'RIGHT' (default: 'RIGHT')", - "enum": ["LEFT", "RIGHT"] + "enum": [ + "LEFT", + "RIGHT" + ] }, "target": { "type": "string", @@ -5054,7 +5860,11 @@ }, { "type": "string", - "enum": ["always", "none", "if-body"], + "enum": [ + "always", + "none", + "if-body" + ], "description": "Controls when AI-generated footer is added to the review body: 'always' (default), 'none' (never), or 'if-body' (only when review has body text)." } ], @@ -5128,7 +5938,7 @@ "oneOf": [ { "type": "object", - "description": "Configuration for resolving review threads on pull requests. Resolution is scoped to the triggering PR only \u2014 threads on other PRs cannot be resolved.", + "description": "Configuration for resolving review threads on pull requests. Resolution is scoped to the triggering PR only — threads on other PRs cannot be resolved.", "properties": { "max": { "type": "integer", @@ -5414,7 +6224,10 @@ "minimum": 1 }, "target": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Target issue/PR to assign agents to. Use 'triggering' (default) for the triggering issue/PR, '*' to require explicit issue_number/pull_number, or a specific issue/PR number. With 'triggering', auto-resolves from github.event.issue.number or github.event.pull_request.number." }, "target-repo": { @@ -5477,7 +6290,10 @@ "minimum": 1 }, "target": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Target issue to assign users to. Use 'triggering' (default) for the triggering issue, '*' to allow any issue, or a specific issue number." }, "target-repo": { @@ -5529,7 +6345,10 @@ "minimum": 1 }, "target": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Target issue to unassign users from. Use 'triggering' (default) for the triggering issue, '*' to allow any issue, or a specific issue number." }, "target-repo": { @@ -5628,7 +6447,10 @@ "description": "Allow updating issue title - presence of key indicates field can be updated" }, "body": { - "type": ["boolean", "null"], + "type": [ + "boolean", + "null" + ], "description": "Allow updating issue body. Set to true to enable body updates, false to disable. For backward compatibility, null (body:) also enables body updates.", "default": true }, @@ -5678,7 +6500,11 @@ "operation": { "type": "string", "description": "Default operation for body updates: 'append' (add to end), 'prepend' (add to start), or 'replace' (overwrite completely). Defaults to 'replace' if not specified.", - "enum": ["append", "prepend", "replace"] + "enum": [ + "append", + "prepend", + "replace" + ] }, "max": { "type": "integer", @@ -5735,7 +6561,11 @@ }, "if-no-changes": { "type": "string", - "enum": ["warn", "error", "ignore"], + "enum": [ + "warn", + "error", + "ignore" + ], "description": "Behavior when no changes to push: 'warn' (default - log warning but succeed), 'error' (fail the action), or 'ignore' (silent success)" }, "commit-title-suffix": { @@ -5749,7 +6579,10 @@ "staged": { "type": "boolean", "description": "If true, emit step summary messages instead of making GitHub API calls for this specific output type (preview mode)", - "examples": [true, false] + "examples": [ + true, + false + ] } }, "additionalProperties": false @@ -5782,7 +6615,13 @@ "description": "List of allowed reasons for hiding comments. Default: all reasons allowed (spam, abuse, off_topic, outdated, resolved).", "items": { "type": "string", - "enum": ["spam", "abuse", "off_topic", "outdated", "resolved"] + "enum": [ + "spam", + "abuse", + "off_topic", + "outdated", + "resolved" + ] } }, "discussions": { @@ -5823,7 +6662,9 @@ "description": "GitHub token to use for dispatching workflows. Overrides global github-token if specified." } }, - "required": ["workflows"], + "required": [ + "workflows" + ], "additionalProperties": false }, { @@ -6053,7 +6894,10 @@ "staged": { "type": "boolean", "description": "If true, emit step summary messages instead of making GitHub API calls (preview mode)", - "examples": [true, false] + "examples": [ + true, + false + ] }, "env": { "type": "object", @@ -6069,7 +6913,11 @@ "github-token": { "$ref": "#/$defs/github_token", "description": "GitHub token to use for safe output jobs. Typically a secret reference like ${{ secrets.GITHUB_TOKEN }} or ${{ secrets.CUSTOM_PAT }}", - "examples": ["${{ secrets.GITHUB_TOKEN }}", "${{ secrets.CUSTOM_PAT }}", "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}"] + "examples": [ + "${{ secrets.GITHUB_TOKEN }}", + "${{ secrets.CUSTOM_PAT }}", + "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" + ] }, "app": { "type": "object", @@ -6078,17 +6926,25 @@ "app-id": { "type": "string", "description": "GitHub App ID. Should reference a variable (e.g., ${{ vars.APP_ID }}).", - "examples": ["${{ vars.APP_ID }}", "${{ secrets.APP_ID }}"] + "examples": [ + "${{ vars.APP_ID }}", + "${{ secrets.APP_ID }}" + ] }, "private-key": { "type": "string", "description": "GitHub App private key. Should reference a secret (e.g., ${{ secrets.APP_PRIVATE_KEY }}).", - "examples": ["${{ secrets.APP_PRIVATE_KEY }}"] + "examples": [ + "${{ secrets.APP_PRIVATE_KEY }}" + ] }, "owner": { "type": "string", "description": "Optional: The owner of the GitHub App installation. If empty, defaults to the current repository owner.", - "examples": ["my-organization", "${{ github.repository_owner }}"] + "examples": [ + "my-organization", + "${{ github.repository_owner }}" + ] }, "repositories": { "type": "array", @@ -6096,10 +6952,21 @@ "items": { "type": "string" }, - "examples": [["repo1", "repo2"], ["my-repo"]] + "examples": [ + [ + "repo1", + "repo2" + ], + [ + "my-repo" + ] + ] } }, - "required": ["app-id", "private-key"], + "required": [ + "app-id", + "private-key" + ], "additionalProperties": false }, "max-patch-size": { @@ -6257,7 +7124,13 @@ }, "type": { "type": "string", - "enum": ["string", "boolean", "choice", "number", "environment"], + "enum": [ + "string", + "boolean", + "choice", + "number", + "environment" + ], "description": "Input parameter type. Supports: string (default), boolean, choice (string with predefined options), number, and environment (string referencing a GitHub environment)", "default": "string" }, @@ -6294,52 +7167,81 @@ "footer": { "type": "string", "description": "Custom footer message template for AI-generated content. Available placeholders: {workflow_name}, {run_url}, {triggering_number}, {workflow_source}, {workflow_source_url}. Example: '> Generated by [{workflow_name}]({run_url})'", - "examples": ["> Generated by [{workflow_name}]({run_url})", "> AI output from [{workflow_name}]({run_url}) for #{triggering_number}"] + "examples": [ + "> Generated by [{workflow_name}]({run_url})", + "> AI output from [{workflow_name}]({run_url}) for #{triggering_number}" + ] }, "footer-install": { "type": "string", "description": "Custom installation instructions template appended to the footer. Available placeholders: {workflow_source}, {workflow_source_url}. Example: '> Install: `gh aw add {workflow_source}`'", - "examples": ["> Install: `gh aw add {workflow_source}`", "> [Add this workflow]({workflow_source_url})"] + "examples": [ + "> Install: `gh aw add {workflow_source}`", + "> [Add this workflow]({workflow_source_url})" + ] }, "footer-workflow-recompile": { "type": "string", "description": "Custom footer message template for workflow recompile issues. Available placeholders: {workflow_name}, {run_url}, {repository}. Example: '> Workflow sync report by [{workflow_name}]({run_url}) for {repository}'", - "examples": ["> Workflow sync report by [{workflow_name}]({run_url}) for {repository}", "> Maintenance report by [{workflow_name}]({run_url})"] + "examples": [ + "> Workflow sync report by [{workflow_name}]({run_url}) for {repository}", + "> Maintenance report by [{workflow_name}]({run_url})" + ] }, "footer-workflow-recompile-comment": { "type": "string", "description": "Custom footer message template for comments on workflow recompile issues. Available placeholders: {workflow_name}, {run_url}, {repository}. Example: '> Update from [{workflow_name}]({run_url}) for {repository}'", - "examples": ["> Update from [{workflow_name}]({run_url}) for {repository}", "> Maintenance update by [{workflow_name}]({run_url})"] + "examples": [ + "> Update from [{workflow_name}]({run_url}) for {repository}", + "> Maintenance update by [{workflow_name}]({run_url})" + ] }, "staged-title": { "type": "string", - "description": "Custom title template for staged mode preview. Available placeholders: {operation}. Example: '\ud83c\udfad Preview: {operation}'", - "examples": ["\ud83c\udfad Preview: {operation}", "## Staged Mode: {operation}"] + "description": "Custom title template for staged mode preview. Available placeholders: {operation}. Example: '🎭 Preview: {operation}'", + "examples": [ + "🎭 Preview: {operation}", + "## Staged Mode: {operation}" + ] }, "staged-description": { "type": "string", "description": "Custom description template for staged mode preview. Available placeholders: {operation}. Example: 'The following {operation} would occur if staged mode was disabled:'", - "examples": ["The following {operation} would occur if staged mode was disabled:"] + "examples": [ + "The following {operation} would occur if staged mode was disabled:" + ] }, "run-started": { "type": "string", "description": "Custom message template for workflow activation comment. Available placeholders: {workflow_name}, {run_url}, {event_type}. Default: 'Agentic [{workflow_name}]({run_url}) triggered by this {event_type}.'", - "examples": ["Agentic [{workflow_name}]({run_url}) triggered by this {event_type}.", "[{workflow_name}]({run_url}) started processing this {event_type}."] + "examples": [ + "Agentic [{workflow_name}]({run_url}) triggered by this {event_type}.", + "[{workflow_name}]({run_url}) started processing this {event_type}." + ] }, "run-success": { "type": "string", - "description": "Custom message template for successful workflow completion. Available placeholders: {workflow_name}, {run_url}. Default: '\u2705 Agentic [{workflow_name}]({run_url}) completed successfully.'", - "examples": ["\u2705 Agentic [{workflow_name}]({run_url}) completed successfully.", "\u2705 [{workflow_name}]({run_url}) finished."] + "description": "Custom message template for successful workflow completion. Available placeholders: {workflow_name}, {run_url}. Default: '✅ Agentic [{workflow_name}]({run_url}) completed successfully.'", + "examples": [ + "✅ Agentic [{workflow_name}]({run_url}) completed successfully.", + "✅ [{workflow_name}]({run_url}) finished." + ] }, "run-failure": { "type": "string", - "description": "Custom message template for failed workflow. Available placeholders: {workflow_name}, {run_url}, {status}. Default: '\u274c Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.'", - "examples": ["\u274c Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.", "\u274c [{workflow_name}]({run_url}) {status}."] + "description": "Custom message template for failed workflow. Available placeholders: {workflow_name}, {run_url}, {status}. Default: '❌ Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.'", + "examples": [ + "❌ Agentic [{workflow_name}]({run_url}) {status} and wasn't able to produce a result.", + "❌ [{workflow_name}]({run_url}) {status}." + ] }, "detection-failure": { "type": "string", - "description": "Custom message template for detection job failure. Available placeholders: {workflow_name}, {run_url}. Default: '\u26a0\ufe0f Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.'", - "examples": ["\u26a0\ufe0f Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.", "\u26a0\ufe0f Detection job failed in [{workflow_name}]({run_url})."] + "description": "Custom message template for detection job failure. Available placeholders: {workflow_name}, {run_url}. Default: '⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.'", + "examples": [ + "⚠️ Security scanning failed for [{workflow_name}]({run_url}). Review the logs for details.", + "⚠️ Detection job failed in [{workflow_name}]({run_url})." + ] }, "append-only-comments": { "type": "boolean", @@ -6393,7 +7295,10 @@ "type": "boolean", "description": "Global footer control for all safe outputs. When false, omits visible AI-generated footer content from all created/updated entities (issues, PRs, discussions, releases) while still including XML markers for searchability. Individual safe-output types (create-issue, update-issue, etc.) can override this by specifying their own footer field. Defaults to true.", "default": true, - "examples": [false, true] + "examples": [ + false, + true + ] }, "runs-on": { "type": "string", @@ -6436,7 +7341,9 @@ "rate-limit": { "type": "object", "description": "Rate limiting configuration to restrict how frequently users can trigger the workflow. Helps prevent abuse and resource exhaustion from programmatically triggered events.", - "required": ["max"], + "required": [ + "max" + ], "properties": { "max": { "type": "integer", @@ -6456,7 +7363,16 @@ "description": "Optional list of event types to apply rate limiting to. If not specified, rate limiting applies to all programmatically triggered events (e.g., workflow_dispatch, issue_comment, pull_request_review).", "items": { "type": "string", - "enum": ["workflow_dispatch", "issue_comment", "pull_request_review", "pull_request_review_comment", "issues", "pull_request", "discussion_comment", "discussion"] + "enum": [ + "workflow_dispatch", + "issue_comment", + "pull_request_review", + "pull_request_review_comment", + "issues", + "pull_request", + "discussion_comment", + "discussion" + ] }, "minItems": 1 }, @@ -6465,7 +7381,13 @@ "description": "Optional list of roles that are exempt from rate limiting. Defaults to ['admin', 'maintain', 'write'] if not specified. Users with any of these roles will not be subject to rate limiting checks. To apply rate limiting to all users, set to an empty array: []", "items": { "type": "string", - "enum": ["admin", "maintain", "write", "triage", "read"] + "enum": [ + "admin", + "maintain", + "write", + "triage", + "read" + ] }, "minItems": 0 } @@ -6479,12 +7401,18 @@ { "max": 10, "window": 30, - "events": ["workflow_dispatch", "issue_comment"] + "events": [ + "workflow_dispatch", + "issue_comment" + ] }, { "max": 5, "window": 60, - "ignored-roles": ["admin", "maintain"] + "ignored-roles": [ + "admin", + "maintain" + ] } ] }, @@ -6493,7 +7421,10 @@ "default": true, "$comment": "Strict mode enforces several security constraints that are validated in Go code (pkg/workflow/strict_mode_validation.go) rather than JSON Schema: (1) Write Permissions + Safe Outputs: When strict=true AND permissions contains write values (contents:write, issues:write, pull-requests:write), safe-outputs must be configured. This relationship is too complex for JSON Schema as it requires checking if ANY permission property has a 'write' value. (2) Network Requirements: When strict=true, the 'network' field must be present and cannot contain standalone wildcard '*' (but patterns like '*.example.com' ARE allowed). (3) MCP Container Network: Custom MCP servers with containers require explicit network configuration. (4) Action Pinning: Actions must be pinned to commit SHAs. These are enforced during compilation via validateStrictMode().", "description": "Enable strict mode validation for enhanced security and compliance. Strict mode enforces: (1) Write Permissions - refuses contents:write, issues:write, pull-requests:write; requires safe-outputs instead, (2) Network Configuration - requires explicit network configuration with no standalone wildcard '*' in allowed domains (patterns like '*.example.com' are allowed), (3) Action Pinning - enforces actions pinned to commit SHAs instead of tags/branches, (4) MCP Network - requires network configuration for custom MCP servers with containers, (5) Deprecated Fields - refuses deprecated frontmatter fields. Can be enabled per-workflow via 'strict: true' in frontmatter, or disabled via 'strict: false'. CLI flag takes precedence over frontmatter (gh aw compile --strict enforces strict mode). Defaults to true. See: https://github.github.com/gh-aw/reference/frontmatter/#strict-mode-strict", - "examples": [true, false] + "examples": [ + true, + false + ] }, "safe-inputs": { "type": "object", @@ -6502,7 +7433,9 @@ "^([a-ln-z][a-z0-9_-]*|m[a-np-z][a-z0-9_-]*|mo[a-ce-z][a-z0-9_-]*|mod[a-df-z][a-z0-9_-]*|mode[a-z0-9_-]+)$": { "type": "object", "description": "Custom tool definition. The key is the tool name (lowercase alphanumeric with dashes/underscores).", - "required": ["description"], + "required": [ + "description" + ], "properties": { "description": { "type": "string", @@ -6516,7 +7449,13 @@ "properties": { "type": { "type": "string", - "enum": ["string", "number", "boolean", "array", "object"], + "enum": [ + "string", + "number", + "boolean", + "array", + "object" + ], "default": "string", "description": "The JSON schema type of the input parameter." }, @@ -6570,71 +7509,108 @@ "description": "Timeout in seconds for tool execution. Default is 60 seconds. Applies to shell (run) and Python (py) tools.", "default": 60, "minimum": 1, - "examples": [30, 60, 120, 300] + "examples": [ + 30, + 60, + 120, + 300 + ] } }, "additionalProperties": false, "oneOf": [ { - "required": ["script"], + "required": [ + "script" + ], "not": { "anyOf": [ { - "required": ["run"] + "required": [ + "run" + ] }, { - "required": ["py"] + "required": [ + "py" + ] }, { - "required": ["go"] + "required": [ + "go" + ] } ] } }, { - "required": ["run"], + "required": [ + "run" + ], "not": { "anyOf": [ { - "required": ["script"] + "required": [ + "script" + ] }, { - "required": ["py"] + "required": [ + "py" + ] }, { - "required": ["go"] + "required": [ + "go" + ] } ] } }, { - "required": ["py"], + "required": [ + "py" + ], "not": { "anyOf": [ { - "required": ["script"] + "required": [ + "script" + ] }, { - "required": ["run"] + "required": [ + "run" + ] }, { - "required": ["go"] + "required": [ + "go" + ] } ] } }, { - "required": ["go"], + "required": [ + "go" + ], "not": { "anyOf": [ { - "required": ["script"] + "required": [ + "script" + ] }, { - "required": ["run"] + "required": [ + "run" + ] }, { - "required": ["py"] + "required": [ + "py" + ] } ] } @@ -6692,9 +7668,18 @@ "description": "Runtime configuration object identified by runtime ID (e.g., 'node', 'python', 'go')", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Runtime version as a string (e.g., '22', '3.12', 'latest') or number (e.g., 22, 3.12). Numeric values are automatically converted to strings at runtime.", - "examples": ["22", "3.12", "latest", 22, 3.12] + "examples": [ + "22", + "3.12", + "latest", + 22, + 3.12 + ] }, "action-repo": { "type": "string", @@ -6707,13 +7692,48 @@ "if": { "type": "string", "description": "Optional GitHub Actions if condition to control when the runtime setup step runs. Supports standard GitHub Actions expression syntax. Useful for conditionally installing runtimes based on file presence (e.g., \"hashFiles('go.mod') != ''\" to install Go only when go.mod exists).", - "examples": ["hashFiles('go.mod') != ''", "hashFiles('package.json') != ''", "hashFiles('requirements.txt') != '' || hashFiles('pyproject.toml') != ''", "hashFiles('uv.lock') != ''", "github.event_name == 'workflow_dispatch'"] + "examples": [ + "hashFiles('go.mod') != ''", + "hashFiles('package.json') != ''", + "hashFiles('requirements.txt') != '' || hashFiles('pyproject.toml') != ''", + "hashFiles('uv.lock') != ''", + "github.event_name == 'workflow_dispatch'" + ] } }, "additionalProperties": false } }, "additionalProperties": false + }, + "roles": { + "description": "Repository access roles required to trigger agentic workflows. Defaults to ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any authenticated user (⚠️ security consideration).", + "oneOf": [ + { + "type": "string", + "enum": [ + "all" + ], + "description": "Allow any authenticated user to trigger the workflow (⚠️ disables permission checking entirely - use with caution)" + }, + { + "type": "array", + "description": "List of repository permission levels that can trigger the workflow. Permission checks are automatically applied to potentially unsafe triggers.", + "items": { + "type": "string", + "enum": [ + "admin", + "maintainer", + "maintain", + "write", + "triage" + ], + "description": "Repository permission level: 'admin' (full access), 'maintainer'/'maintain' (repository management), 'write' (push access), 'triage' (issue management)" + }, + "minItems": 1, + "maxItems": 50 + } + ] } }, "additionalProperties": false, @@ -6732,7 +7752,9 @@ } } }, - "required": ["slash_command"] + "required": [ + "slash_command" + ] }, { "properties": { @@ -6742,7 +7764,9 @@ } } }, - "required": ["command"] + "required": [ + "command" + ] } ] } @@ -6761,7 +7785,9 @@ } } }, - "required": ["issue_comment"] + "required": [ + "issue_comment" + ] }, { "properties": { @@ -6771,7 +7797,9 @@ } } }, - "required": ["pull_request_review_comment"] + "required": [ + "pull_request_review_comment" + ] }, { "properties": { @@ -6781,7 +7809,9 @@ } } }, - "required": ["label"] + "required": [ + "label" + ] } ] } @@ -6815,7 +7845,11 @@ "oneOf": [ { "type": "string", - "enum": ["claude", "codex", "copilot"], + "enum": [ + "claude", + "codex", + "copilot" + ], "description": "Simple engine name: 'claude' (default, Claude Code), 'copilot' (GitHub Copilot CLI), or 'codex' (OpenAI Codex CLI)" }, { @@ -6824,13 +7858,25 @@ "properties": { "id": { "type": "string", - "enum": ["claude", "codex", "copilot"], + "enum": [ + "claude", + "codex", + "copilot" + ], "description": "AI engine identifier: 'claude' (Claude Code), 'codex' (OpenAI Codex CLI), or 'copilot' (GitHub Copilot CLI)" }, "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional version of the AI engine action (e.g., 'beta', 'stable', 20). Has sensible defaults and can typically be omitted. Numeric values are automatically converted to strings at runtime.", - "examples": ["beta", "stable", 20, 3.11] + "examples": [ + "beta", + "stable", + 20, + 3.11 + ] }, "model": { "type": "string", @@ -6868,7 +7914,9 @@ "description": "Whether to cancel in-progress runs of the same concurrency group. Defaults to false for agentic workflow runs." } }, - "required": ["group"], + "required": [ + "group" + ], "additionalProperties": false } ], @@ -6927,7 +7975,9 @@ "description": "Human-readable description of what this pattern matches" } }, - "required": ["pattern"], + "required": [ + "pattern" + ], "additionalProperties": false } }, @@ -6947,7 +7997,9 @@ "description": "Optional array of command-line arguments to pass to the AI engine CLI. These arguments are injected after all other args but before the prompt." } }, - "required": ["id"], + "required": [ + "id" + ], "additionalProperties": false } ] @@ -6958,13 +8010,18 @@ "properties": { "type": { "type": "string", - "enum": ["stdio", "local"], + "enum": [ + "stdio", + "local" + ], "description": "MCP connection type for stdio (local is an alias for stdio)" }, "registry": { "type": "string", "description": "URI to the installation location when MCP is installed from a registry", - "examples": ["https://api.mcp.github.com/v0/servers/microsoft/markitdown"] + "examples": [ + "https://api.mcp.github.com/v0/servers/microsoft/markitdown" + ] }, "command": { "type": "string", @@ -6979,9 +8036,17 @@ "description": "Container image for stdio MCP connections" }, "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Optional version/tag for the container image (e.g., 'latest', 'v1.0.0', 20, 3.11). Numeric values are automatically converted to strings at runtime.", - "examples": ["latest", "v1.0.0", 20, 3.11] + "examples": [ + "latest", + "v1.0.0", + 20, + 3.11 + ] }, "args": { "type": "array", @@ -6993,7 +8058,11 @@ "entrypoint": { "type": "string", "description": "Optional entrypoint override for container (equivalent to docker run --entrypoint)", - "examples": ["/bin/sh", "/custom/entrypoint.sh", "python"] + "examples": [ + "/bin/sh", + "/custom/entrypoint.sh", + "python" + ] }, "entrypointArgs": { "type": "array", @@ -7009,7 +8078,15 @@ "pattern": "^[^:]+:[^:]+:(ro|rw)$" }, "description": "Volume mounts for container in format 'source:dest:mode' where mode is 'ro' or 'rw'", - "examples": [["/tmp/data:/data:ro"], ["/workspace:/workspace:rw", "/config:/config:ro"]] + "examples": [ + [ + "/tmp/data:/data:ro" + ], + [ + "/workspace:/workspace:rw", + "/config:/config:ro" + ] + ] }, "env": { "type": "object", @@ -7055,29 +8132,50 @@ "items": { "type": "string" }, - "examples": [["*"], ["store_memory", "retrieve_memory"], ["brave_web_search"]] + "examples": [ + [ + "*" + ], + [ + "store_memory", + "retrieve_memory" + ], + [ + "brave_web_search" + ] + ] } }, "additionalProperties": false, "$comment": "Validation constraints: (1) Mutual exclusion: 'command' and 'container' cannot both be specified. (2) Requirement: Either 'command' or 'container' must be provided (via 'anyOf'). (3) Type constraint: When 'type' is 'stdio' or 'local', either 'command' or 'container' is required. Note: Per-server 'network' field is deprecated and ignored.", "anyOf": [ { - "required": ["type"] + "required": [ + "type" + ] }, { - "required": ["command"] + "required": [ + "command" + ] }, { - "required": ["container"] + "required": [ + "container" + ] } ], "not": { "allOf": [ { - "required": ["command"] + "required": [ + "command" + ] }, { - "required": ["container"] + "required": [ + "container" + ] } ] }, @@ -7086,17 +8184,24 @@ "if": { "properties": { "type": { - "enum": ["stdio", "local"] + "enum": [ + "stdio", + "local" + ] } } }, "then": { "anyOf": [ { - "required": ["command"] + "required": [ + "command" + ] }, { - "required": ["container"] + "required": [ + "container" + ] } ] } @@ -7109,13 +8214,17 @@ "properties": { "type": { "type": "string", - "enum": ["http"], + "enum": [ + "http" + ], "description": "MCP connection type for HTTP" }, "registry": { "type": "string", "description": "URI to the installation location when MCP is installed from a registry", - "examples": ["https://api.mcp.github.com/v0/servers/microsoft/markitdown"] + "examples": [ + "https://api.mcp.github.com/v0/servers/microsoft/markitdown" + ] }, "url": { "type": "string", @@ -7138,17 +8247,34 @@ "items": { "type": "string" }, - "examples": [["*"], ["store_memory", "retrieve_memory"], ["brave_web_search"]] + "examples": [ + [ + "*" + ], + [ + "store_memory", + "retrieve_memory" + ], + [ + "brave_web_search" + ] + ] } }, - "required": ["url"], + "required": [ + "url" + ], "additionalProperties": false }, "github_token": { "type": "string", "pattern": "^\\$\\{\\{\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*(\\s*\\|\\|\\s*secrets\\.[A-Za-z_][A-Za-z0-9_]*)*\\s*\\}\\}$", "description": "GitHub token expression using secrets. Pattern details: `[A-Za-z_][A-Za-z0-9_]*` matches a valid secret name (starts with a letter or underscore, followed by letters, digits, or underscores). The full pattern matches expressions like `${{ secrets.NAME }}` or `${{ secrets.NAME1 || secrets.NAME2 }}`.", - "examples": ["${{ secrets.GITHUB_TOKEN }}", "${{ secrets.CUSTOM_PAT }}", "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}"] + "examples": [ + "${{ secrets.GITHUB_TOKEN }}", + "${{ secrets.CUSTOM_PAT }}", + "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" + ] }, "githubActionsStep": { "type": "object", @@ -7209,10 +8335,14 @@ "additionalProperties": false, "anyOf": [ { - "required": ["uses"] + "required": [ + "uses" + ] }, { - "required": ["run"] + "required": [ + "run" + ] } ] } diff --git a/pkg/workflow/role_checks.go b/pkg/workflow/role_checks.go index a326247072..00f6fe473a 100644 --- a/pkg/workflow/role_checks.go +++ b/pkg/workflow/role_checks.go @@ -89,7 +89,15 @@ func (c *Compiler) generateRateLimitCheck(data *WorkflowData, steps []string) [] // extractRoles extracts the 'roles' field from frontmatter to determine permission requirements func (c *Compiler) extractRoles(frontmatter map[string]any) []string { - // Check on.roles + // Check top-level roles first + if rolesValue, exists := frontmatter["roles"]; exists { + roles := parseRolesValue(rolesValue, "roles") + if roles != nil { + return roles + } + } + + // Check on.roles (legacy location) if onValue, exists := frontmatter["on"]; exists { if onMap, ok := onValue.(map[string]any); ok { if rolesValue, hasRoles := onMap["roles"]; hasRoles {