diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 19fd381c4a..30ed230496 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -33,7 +33,7 @@ # - shared/mcp/tavily.md # - shared/reporting.md # -# frontmatter-hash: f7ac4463883c01199c0d5d1279fe2380151a3a19d709d279a4e732f58cf9edc1 +# frontmatter-hash: 90fb617d079124ba24620497f43ca5f1373dce2f5577a2cc5d7ae5492a47b3fb name: "Smoke Claude" "on": @@ -320,7 +320,7 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF' - {"add_comment":{"max":2},"add_labels":{"allowed":["smoke-claude"],"max":3},"create_issue":{"expires":2,"group":true,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}} + {"add_comment":{"max":2},"add_labels":{"allowed":["smoke-claude"],"max":3},"add_reviewer":{"max":2},"create_issue":{"expires":2,"group":true,"max":1},"create_pull_request_review_comment":{"max":5},"missing_data":{},"missing_tool":{},"noop":{"max":1},"push_to_pull_request_branch":{"max":0,"target":"*"},"resolve_pull_request_review_thread":{"max":5},"submit_pull_request_review":{"max":1},"update_pull_request":{"max":1}} GH_AW_SAFE_OUTPUTS_CONFIG_EOF cat > /opt/gh-aw/safeoutputs/tools.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_EOF' [ @@ -365,6 +365,30 @@ jobs: }, "name": "create_issue" }, + { + "description": "Close a pull request WITHOUT merging, adding a closing comment. You can and should always add a comment when closing a PR to explain the action or provide context. Use this for PRs that should be abandoned, superseded, or closed for other reasons. The closing comment should explain why the PR is being closed. This does NOT merge the changes. If the PR is already closed, a comment will still be posted. CONSTRAINTS: Maximum 1 pull request(s) can be closed.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Closing comment explaining why the PR is being closed without merging (e.g., superseded by another PR, no longer needed, approach rejected).", + "type": "string" + }, + "pull_request_number": { + "description": "Pull request number to close. This is the numeric ID from the GitHub URL (e.g., 432 in github.com/owner/repo/pull/432). If omitted, closes the PR that triggered this workflow (requires a pull_request event trigger).", + "type": [ + "number", + "string" + ] + } + }, + "required": [ + "body" + ], + "type": "object" + }, + "name": "close_pull_request" + }, { "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. CONSTRAINTS: Maximum 2 comment(s) can be added.", "inputSchema": { @@ -386,6 +410,91 @@ jobs: }, "name": "add_comment" }, + { + "description": "Create a review comment on a specific line of code in a pull request. Use this for inline code review feedback, suggestions, or questions about specific code changes. For general PR comments not tied to specific lines, use add_comment instead. CONSTRAINTS: Maximum 5 review comment(s) can be created. Comments will be on the RIGHT side of the diff.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Review comment content in Markdown. Provide specific, actionable feedback about the code at this location.", + "type": "string" + }, + "line": { + "description": "Line number for the comment. For single-line comments, this is the target line. For multi-line comments, this is the ending line.", + "type": [ + "number", + "string" + ] + }, + "path": { + "description": "File path relative to the repository root (e.g., 'src/auth/login.js'). Must be a file that was changed in the PR.", + "type": "string" + }, + "side": { + "description": "Side of the diff to comment on: RIGHT for the new version (additions), LEFT for the old version (deletions). Defaults to RIGHT.", + "enum": [ + "LEFT", + "RIGHT" + ], + "type": "string" + }, + "start_line": { + "description": "Starting line number for multi-line comments. When set, the comment spans from start_line to line. Omit for single-line comments.", + "type": [ + "number", + "string" + ] + } + }, + "required": [ + "path", + "line", + "body" + ], + "type": "object" + }, + "name": "create_pull_request_review_comment" + }, + { + "description": "Submit a pull request review with a status decision. All create_pull_request_review_comment outputs are automatically collected and included as inline comments in this review. Use APPROVE to approve the PR, REQUEST_CHANGES to request changes, or COMMENT for general feedback without a decision. If you don't call this tool, review comments are still submitted as a COMMENT review. CONSTRAINTS: Maximum 1 review(s) can be submitted.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Overall review summary in Markdown. Provide a high-level assessment of the changes. Required for REQUEST_CHANGES; optional for APPROVE and COMMENT.", + "type": "string" + }, + "event": { + "description": "Review decision: APPROVE to approve the pull request, REQUEST_CHANGES to formally request changes before merging, or COMMENT for general feedback without a formal decision. Defaults to COMMENT when omitted.", + "enum": [ + "APPROVE", + "REQUEST_CHANGES", + "COMMENT" + ], + "type": "string" + } + }, + "type": "object" + }, + "name": "submit_pull_request_review" + }, + { + "description": "Resolve a review thread on a pull request. Use this to mark a review conversation as resolved after addressing the feedback. The thread_id must be the node ID of the review thread (e.g., PRRT_kwDO...). CONSTRAINTS: Maximum 5 review thread(s) can be resolved.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "thread_id": { + "description": "The node ID of the review thread to resolve (e.g., 'PRRT_kwDOABCD...'). This is the GraphQL node ID, not a numeric ID.", + "type": "string" + } + }, + "required": [ + "thread_id" + ], + "type": "object" + }, + "name": "resolve_pull_request_review_thread" + }, { "description": "Add labels to an existing GitHub issue or pull request for categorization and filtering. Labels must already exist in the repository. For creating new issues with labels, use create_issue with the labels property instead. CONSTRAINTS: Only these labels are allowed: [smoke-claude].", "inputSchema": { @@ -407,6 +516,95 @@ jobs: }, "name": "add_labels" }, + { + "description": "Add reviewers to a GitHub pull request. Reviewers receive notifications and can approve or request changes. Use 'copilot' as a reviewer name to request the Copilot PR review bot. CONSTRAINTS: Maximum 2 reviewer(s) can be added.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "pull_request_number": { + "description": "Pull request number to add reviewers to. This is the numeric ID from the GitHub URL (e.g., 876 in github.com/owner/repo/pull/876). If omitted, adds reviewers to the PR that triggered this workflow.", + "type": [ + "number", + "string" + ] + }, + "reviewers": { + "description": "GitHub usernames to add as reviewers (e.g., ['octocat', 'copilot']). Users must have access to the repository.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "reviewers" + ], + "type": "object" + }, + "name": "add_reviewer" + }, + { + "description": "Update an existing GitHub pull request's title or body. Supports replacing, appending to, or prepending content to the body. Title is always replaced. Only the fields you specify will be updated; other fields remain unchanged. CONSTRAINTS: Maximum 1 pull request(s) can be updated. Target: *.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Pull request body content in Markdown. For 'replace', this becomes the entire body. For 'append'/'prepend', this is added with a separator.", + "type": "string" + }, + "operation": { + "description": "How to update the PR body: 'replace' (default - completely overwrite), 'append' (add to end with separator), or 'prepend' (add to start with separator). Title is always replaced.", + "enum": [ + "replace", + "append", + "prepend" + ], + "type": "string" + }, + "pull_request_number": { + "description": "Pull request number to update. This is the numeric ID from the GitHub URL (e.g., 234 in github.com/owner/repo/pull/234). Required when the workflow target is '*' (any PR).", + "type": [ + "number", + "string" + ] + }, + "title": { + "description": "New pull request title to replace the existing title.", + "type": "string" + } + }, + "type": "object" + }, + "name": "update_pull_request" + }, + { + "description": "Push committed changes to a pull request's branch. Use this to add follow-up commits to an existing PR, such as addressing review feedback or fixing issues. Changes must be committed locally before calling this tool.", + "inputSchema": { + "additionalProperties": false, + "properties": { + "branch": { + "description": "Branch name to push changes from. If omitted, uses the current working branch. Only specify if you need to push from a different branch.", + "type": "string" + }, + "message": { + "description": "Commit message describing the changes. Follow repository commit message conventions (e.g., conventional commits).", + "type": "string" + }, + "pull_request_number": { + "description": "Pull request number to push changes to. This is the numeric ID from the GitHub URL (e.g., 654 in github.com/owner/repo/pull/654). Required when the workflow target is '*' (any PR).", + "type": [ + "number", + "string" + ] + } + }, + "required": [ + "message" + ], + "type": "object" + }, + "name": "push_to_pull_request_branch" + }, { "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", "inputSchema": { @@ -509,6 +707,21 @@ jobs: } } }, + "add_reviewer": { + "defaultMax": 3, + "fields": { + "pull_request_number": { + "issueOrPRNumber": true + }, + "reviewers": { + "required": true, + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 39 + } + } + }, "create_issue": { "defaultMax": 1, "fields": { @@ -542,6 +755,36 @@ jobs: } } }, + "create_pull_request_review_comment": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "line": { + "required": true, + "positiveInteger": true + }, + "path": { + "required": true, + "type": "string" + }, + "side": { + "type": "string", + "enum": [ + "LEFT", + "RIGHT" + ] + }, + "start_line": { + "optionalPositiveInteger": true + } + }, + "customValidation": "startLineLessOrEqualLine" + }, "missing_tool": { "defaultMax": 20, "fields": { @@ -573,6 +816,80 @@ jobs: "maxLength": 65000 } } + }, + "push_to_pull_request_branch": { + "defaultMax": 1, + "fields": { + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "message": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "pull_request_number": { + "issueOrPRNumber": true + } + } + }, + "resolve_pull_request_review_thread": { + "defaultMax": 10, + "fields": { + "thread_id": { + "required": true, + "type": "string" + } + } + }, + "submit_pull_request_review": { + "defaultMax": 1, + "fields": { + "body": { + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "event": { + "type": "string", + "enum": [ + "APPROVE", + "REQUEST_CHANGES", + "COMMENT" + ] + } + } + }, + "update_pull_request": { + "defaultMax": 1, + "fields": { + "body": { + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "operation": { + "type": "string", + "enum": [ + "replace", + "append", + "prepend" + ] + }, + "pull_request_number": { + "issueOrPRNumber": true + }, + "title": { + "type": "string", + "sanitize": true, + "maxLength": 256 + } + }, + "customValidation": "requiresOneOf:title,body" } } GH_AW_SAFE_OUTPUTS_VALIDATION_EOF @@ -1562,7 +1879,7 @@ jobs: run: | set -o pipefail sudo -E awf --tty --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,anthropic.com,api.anthropic.com,api.github.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,cdn.playwright.dev,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,ghcr.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,go.dev,golang.org,goproxy.io,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,mcp.tavily.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,playwright.download.prss.microsoft.com,ppa.launchpad.net,proxy.golang.org,pypi.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,sentry.io,statsig.anthropic.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.17.0 --skip-pull \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --max-turns 50 --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools '\''Bash,BashOutput,Edit,Edit(/tmp/gh-aw/cache-memory/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/gh-aw/cache-memory/*),NotebookEdit,NotebookRead,Read,Read(/tmp/gh-aw/cache-memory/*),Task,TodoWrite,Write,Write(/tmp/gh-aw/cache-memory/*),mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users,mcp__playwright__browser_click,mcp__playwright__browser_close,mcp__playwright__browser_console_messages,mcp__playwright__browser_drag,mcp__playwright__browser_evaluate,mcp__playwright__browser_file_upload,mcp__playwright__browser_fill_form,mcp__playwright__browser_handle_dialog,mcp__playwright__browser_hover,mcp__playwright__browser_install,mcp__playwright__browser_navigate,mcp__playwright__browser_navigate_back,mcp__playwright__browser_network_requests,mcp__playwright__browser_press_key,mcp__playwright__browser_resize,mcp__playwright__browser_select_option,mcp__playwright__browser_snapshot,mcp__playwright__browser_tabs,mcp__playwright__browser_take_screenshot,mcp__playwright__browser_type,mcp__playwright__browser_wait_for,mcp__tavily'\'' --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && claude --print --disable-slash-commands --no-chrome --max-turns 100 --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json --allowed-tools '\''Bash,BashOutput,Edit,Edit(/tmp/gh-aw/cache-memory/*),ExitPlanMode,Glob,Grep,KillBash,LS,MultiEdit,MultiEdit(/tmp/gh-aw/cache-memory/*),NotebookEdit,NotebookRead,Read,Read(/tmp/gh-aw/cache-memory/*),Task,TodoWrite,Write,Write(/tmp/gh-aw/cache-memory/*),mcp__github__download_workflow_run_artifact,mcp__github__get_code_scanning_alert,mcp__github__get_commit,mcp__github__get_dependabot_alert,mcp__github__get_discussion,mcp__github__get_discussion_comments,mcp__github__get_file_contents,mcp__github__get_job_logs,mcp__github__get_label,mcp__github__get_latest_release,mcp__github__get_me,mcp__github__get_notification_details,mcp__github__get_pull_request,mcp__github__get_pull_request_comments,mcp__github__get_pull_request_diff,mcp__github__get_pull_request_files,mcp__github__get_pull_request_review_comments,mcp__github__get_pull_request_reviews,mcp__github__get_pull_request_status,mcp__github__get_release_by_tag,mcp__github__get_secret_scanning_alert,mcp__github__get_tag,mcp__github__get_workflow_run,mcp__github__get_workflow_run_logs,mcp__github__get_workflow_run_usage,mcp__github__issue_read,mcp__github__list_branches,mcp__github__list_code_scanning_alerts,mcp__github__list_commits,mcp__github__list_dependabot_alerts,mcp__github__list_discussion_categories,mcp__github__list_discussions,mcp__github__list_issue_types,mcp__github__list_issues,mcp__github__list_label,mcp__github__list_notifications,mcp__github__list_pull_requests,mcp__github__list_releases,mcp__github__list_secret_scanning_alerts,mcp__github__list_starred_repositories,mcp__github__list_tags,mcp__github__list_workflow_jobs,mcp__github__list_workflow_run_artifacts,mcp__github__list_workflow_runs,mcp__github__list_workflows,mcp__github__pull_request_read,mcp__github__search_code,mcp__github__search_issues,mcp__github__search_orgs,mcp__github__search_pull_requests,mcp__github__search_repositories,mcp__github__search_users,mcp__playwright__browser_click,mcp__playwright__browser_close,mcp__playwright__browser_console_messages,mcp__playwright__browser_drag,mcp__playwright__browser_evaluate,mcp__playwright__browser_file_upload,mcp__playwright__browser_fill_form,mcp__playwright__browser_handle_dialog,mcp__playwright__browser_hover,mcp__playwright__browser_install,mcp__playwright__browser_navigate,mcp__playwright__browser_navigate_back,mcp__playwright__browser_network_requests,mcp__playwright__browser_press_key,mcp__playwright__browser_resize,mcp__playwright__browser_select_option,mcp__playwright__browser_snapshot,mcp__playwright__browser_tabs,mcp__playwright__browser_take_screenshot,mcp__playwright__browser_type,mcp__playwright__browser_wait_for,mcp__tavily'\'' --debug-file /tmp/gh-aw/agent-stdio.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_CLAUDE:+ --model "$GH_AW_MODEL_AGENT_CLAUDE"}' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} BASH_DEFAULT_TIMEOUT_MS: 60000 @@ -1571,7 +1888,7 @@ jobs: DISABLE_BUG_COMMAND: 1 DISABLE_ERROR_REPORTING: 1 DISABLE_TELEMETRY: 1 - GH_AW_MAX_TURNS: 50 + GH_AW_MAX_TURNS: 100 GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/mcp-servers.json GH_AW_MODEL_AGENT_CLAUDE: ${{ vars.GH_AW_MODEL_AGENT_CLAUDE || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt @@ -1705,6 +2022,7 @@ jobs: /tmp/gh-aw/sandbox/firewall/logs/ /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ + /tmp/gh-aw/aw.patch if-no-files-found: ignore conclusion: @@ -1717,7 +2035,7 @@ jobs: if: (always()) && (needs.agent.result != 'skipped') runs-on: ubuntu-slim permissions: - contents: read + contents: write discussions: write issues: write pull-requests: write @@ -1920,7 +2238,7 @@ jobs: run: | set -o pipefail # Execute Claude Code CLI with prompt from file - claude --print --disable-slash-commands --no-chrome --max-turns 50 --allowed-tools 'Bash(cat),Bash(grep),Bash(head),Bash(jq),Bash(ls),Bash(tail),Bash(wc),BashOutput,ExitPlanMode,Glob,Grep,KillBash,LS,NotebookRead,Read,Task,TodoWrite' --debug-file /tmp/gh-aw/threat-detection/detection.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_CLAUDE:+ --model "$GH_AW_MODEL_DETECTION_CLAUDE"} 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log + claude --print --disable-slash-commands --no-chrome --max-turns 100 --allowed-tools 'Bash(cat),Bash(grep),Bash(head),Bash(jq),Bash(ls),Bash(tail),Bash(wc),BashOutput,ExitPlanMode,Glob,Grep,KillBash,LS,NotebookRead,Read,Task,TodoWrite' --debug-file /tmp/gh-aw/threat-detection/detection.log --verbose --permission-mode bypassPermissions --output-format stream-json "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_DETECTION_CLAUDE:+ --model "$GH_AW_MODEL_DETECTION_CLAUDE"} 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} BASH_DEFAULT_TIMEOUT_MS: 60000 @@ -1929,7 +2247,7 @@ jobs: DISABLE_BUG_COMMAND: 1 DISABLE_ERROR_REPORTING: 1 DISABLE_TELEMETRY: 1 - GH_AW_MAX_TURNS: 50 + GH_AW_MAX_TURNS: 100 GH_AW_MODEL_DETECTION_CLAUDE: ${{ vars.GH_AW_MODEL_DETECTION_CLAUDE || '' }} GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt GITHUB_WORKSPACE: ${{ github.workspace }} @@ -2003,12 +2321,13 @@ jobs: safe_outputs: needs: + - activation - agent - detection if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true') runs-on: ubuntu-slim permissions: - contents: read + contents: write discussions: write issues: write pull-requests: write @@ -2019,6 +2338,7 @@ jobs: GH_AW_WORKFLOW_ID: "smoke-claude" GH_AW_WORKFLOW_NAME: "Smoke Claude" outputs: + add_reviewer_reviewers_added: ${{ steps.process_safe_outputs.outputs.reviewers_added }} create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} @@ -2045,12 +2365,38 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: agent-artifacts + path: /tmp/gh-aw/ + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 1 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + GIT_TOKEN: ${{ github.token }} + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + # Re-authenticate git with GitHub token + SERVER_URL_STRIPPED="${SERVER_URL#https://}" + git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Process Safe Outputs id: process_safe_outputs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-claude\"]},\"create_issue\":{\"close_older_issues\":true,\"expires\":2,\"group\":true,\"max\":1},\"missing_data\":{},\"missing_tool\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-claude\"]},\"close_pull_request\":{\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"expires\":2,\"group\":true,\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"push_to_pull_request_branch\":{\"base_branch\":\"${{ github.ref_name }}\",\"if_no_changes\":\"warn\",\"max_patch_size\":1024,\"target\":\"*\"},\"resolve_pull_request_review_thread\":{\"max\":5},\"submit_pull_request_review\":{\"footer\":true,\"max\":1},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":true,\"max\":1,\"target\":\"*\"}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/smoke-claude.md b/.github/workflows/smoke-claude.md index 3610c113d3..6552c696a5 100644 --- a/.github/workflows/smoke-claude.md +++ b/.github/workflows/smoke-claude.md @@ -17,7 +17,7 @@ permissions: name: Smoke Claude engine: id: claude - max-turns: 50 + max-turns: 100 strict: true imports: - shared/mcp-pagination.md @@ -62,6 +62,30 @@ safe-outputs: close-older-issues: true add-labels: allowed: [smoke-claude] + update-pull-request: + title: true + body: true + max: 1 + target: "*" + close-pull-request: + staged: true + max: 1 + create-pull-request-review-comment: + max: 5 + side: "RIGHT" + target: "*" + submit-pull-request-review: + max: 1 + footer: true + resolve-pull-request-review-thread: + max: 5 + push-to-pull-request-branch: + staged: true + target: "*" + if-no-changes: "warn" + add-reviewer: + max: 2 + target: "*" messages: footer: "> šŸ’„ *[THE END] — Illustrated by [{workflow_name}]({run_url})*" run-started: "šŸ’„ **WHOOSH!** [{workflow_name}]({run_url}) springs into action on this {event_type}! *[Panel 1 begins...]*" @@ -97,6 +121,51 @@ timeout-minutes: 10 - Write a summary of the results to `/tmp/gh-aw/agent/smoke-claude-status-${{ github.run_id }}.txt` (create directory if needed) - Use bash to verify the file was created and display its contents +## PR Review Safe Outputs Testing + +**IMPORTANT**: The following tests require an open pull request. First, use the GitHub MCP tool to find an open PR in ${{ github.repository }} (or use the triggering PR if this is a pull_request event). Store the PR number for use in subsequent tests. + +11. **Update PR Testing**: Use the `update_pull_request` tool to update the PR's body by appending a test message: "✨ PR Review Safe Output Test - Run ${{ github.run_id }}" + - Use `pr_number: ` to target the open PR + - Use `operation: "append"` and `body: "\n\n---\n✨ PR Review Safe Output Test - Run ${{ github.run_id }}"` + - Verify the tool call succeeds + +12. **PR Review Comment Testing**: Use the `create_pull_request_review_comment` tool to add review comments on the PR + - Find a file in the PR's diff (use GitHub MCP to get PR files) + - Add at least 2 review comments on different lines with constructive feedback + - Use `pr_number: `, `path: ""`, `line: `, and `body: ""` + - Verify the tool calls succeed + +13. **Submit PR Review Testing**: Use the `submit_pull_request_review` tool to submit a consolidated review + - Use `pr_number: `, `event: "COMMENT"`, and `body: "šŸ’„ Automated smoke test review - all systems nominal!"` + - Verify the review is submitted successfully + - Note: This will bundle all review comments from test #12 + +14. **Resolve Review Thread Testing**: + - Use the GitHub MCP tool to list review threads on the PR + - If any threads exist, use the `resolve_pull_request_review_thread` tool to resolve one thread + - Use `thread_id: ""` from an existing thread + - If no threads exist, mark this test as āš ļø (skipped - no threads to resolve) + +15. **Add Reviewer Testing**: Use the `add_reviewer` tool to add a reviewer to the PR + - Use `pr_number: ` and `reviewers: ["copilot"]` (or another valid reviewer) + - Verify the tool call succeeds + - Note: May fail if reviewer is already assigned or doesn't have access + +16. **Push to PR Branch Testing**: + - Create a test file at `/tmp/test-pr-push-${{ github.run_id }}.txt` with content "Test file for PR push" + - Use git commands to check if we're on the PR branch + - Use the `push_to_pull_request_branch` tool to push this change + - Use `pr_number: ` and `commit_message: "test: Add smoke test file"` + - Verify the push succeeds + - Note: This test may be skipped if not on a PR branch or if the PR is from a fork + +17. **Close PR Testing** (CONDITIONAL - only if a test PR exists): + - If you can identify a test/bot PR that can be safely closed, use the `close_pull_request` tool + - Use `pr_number: ` and `comment: "Closing as part of smoke test - Run ${{ github.run_id }}"` + - If no suitable test PR exists, mark this test as āš ļø (skipped - no safe PR to close) + - **DO NOT close the triggering PR or any important PRs** + ## Output **CRITICAL: You MUST create an issue regardless of test results - this is a required safe output.** @@ -104,19 +173,20 @@ timeout-minutes: 10 1. **ALWAYS create an issue** with a summary of the smoke test run: - Title: "Smoke Test: Claude - ${{ github.run_id }}" - Body should include: - - Test results (āœ… or āŒ for each test) - - Overall status: PASS or FAIL + - Test results (āœ… for pass, āŒ for fail, āš ļø for skipped) for each test (including PR review tests #11-17) + - Overall status: PASS (all passed), PARTIAL (some skipped), or FAIL (any failed) - Run URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - Timestamp + - Note which PR was used for PR review testing (if applicable) - If ANY test fails, include error details in the issue body - This issue MUST be created before any other safe output operations 2. **Only if this workflow was triggered by a pull_request event**: Use the `add_comment` tool to add a **very brief** comment (max 5-10 lines) to the triggering pull request (omit the `item_number` parameter to auto-target the triggering PR) with: - - PR titles only (no descriptions) - - āœ… or āŒ for each test result - - Overall status: PASS or FAIL + - Test results for core tests #1-10 (āœ… or āŒ) + - Test results for PR review tests #11-17 (āœ…, āŒ, or āš ļø) + - Overall status: PASS, PARTIAL, or FAIL 3. Use the `add_comment` tool with `item_number` set to the discussion number you extracted in step 9 to add a **fun comic-book style comment** to that discussion - be playful and use comic-book language like "šŸ’„ WHOOSH!" - If step 9 failed to extract a discussion number, skip this step -If all tests pass, use the `add_labels` tool to add the label `smoke-claude` to the pull request (omit the `item_number` parameter to auto-target the triggering PR if this workflow was triggered by a pull_request event). +If all non-skipped tests pass, use the `add_labels` tool to add the label `smoke-claude` to the pull request (omit the `item_number` parameter to auto-target the triggering PR if this workflow was triggered by a pull_request event). diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index 782e864a4a..f46ddb3ace 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", @@ -1354,17 +1627,37 @@ "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" + ] } }, "additionalProperties": false, @@ -1380,25 +1673,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" + ] } } ] @@ -1425,7 +1730,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)" }, { @@ -1435,82 +1743,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." } } @@ -1520,7 +1889,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", @@ -1563,10 +1935,14 @@ "additionalProperties": false, "oneOf": [ { - "required": ["uses"] + "required": [ + "uses" + ] }, { - "required": ["run"] + "required": [ + "run" + ] } ], "properties": { @@ -1779,17 +2155,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", @@ -1797,7 +2182,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", @@ -1813,7 +2201,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 }}", @@ -1882,7 +2272,9 @@ { "type": "object", "description": "Secret with metadata", - "required": ["value"], + "required": [ + "value" + ], "properties": { "value": { "type": "string", @@ -1934,7 +2326,9 @@ "description": "A deployment URL" } }, - "required": ["name"], + "required": [ + "name" + ], "additionalProperties": false } ] @@ -2002,7 +2396,9 @@ "description": "Additional Docker container options" } }, - "required": ["image"], + "required": [ + "image" + ], "additionalProperties": false } ] @@ -2072,7 +2468,9 @@ "description": "Additional Docker container options" } }, - "required": ["image"], + "required": [ + "image" + ], "additionalProperties": false } ] @@ -2084,13 +2482,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" @@ -2100,7 +2509,9 @@ "oneOf": [ { "type": "string", - "enum": ["defaults"], + "enum": [ + "defaults" + ], "description": "Use default network permissions (basic infrastructure: certificates, JSON schema, Ubuntu, etc.)" }, { @@ -2140,7 +2551,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)" }, { @@ -2155,14 +2568,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", @@ -2177,7 +2603,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 @@ -2194,7 +2625,12 @@ "oneOf": [ { "type": "string", - "enum": ["default", "sandbox-runtime", "awf", "srt"], + "enum": [ + "default", + "sandbox-runtime", + "awf", + "srt" + ], "description": "Legacy string format for sandbox type: 'default' for no sandbox, 'sandbox-runtime' or 'srt' for Anthropic Sandbox Runtime, 'awf' for Agent Workflow Firewall" }, { @@ -2203,7 +2639,12 @@ "properties": { "type": { "type": "string", - "enum": ["default", "sandbox-runtime", "awf", "srt"], + "enum": [ + "default", + "sandbox-runtime", + "awf", + "srt" + ], "description": "Legacy sandbox type field (use agent instead)" }, "agent": { @@ -2217,7 +2658,10 @@ }, { "type": "string", - "enum": ["awf", "srt"], + "enum": [ + "awf", + "srt" + ], "description": "Sandbox type: 'awf' for Agent Workflow Firewall, 'srt' for Sandbox Runtime" }, { @@ -2226,12 +2670,18 @@ "properties": { "id": { "type": "string", - "enum": ["awf", "srt"], + "enum": [ + "awf", + "srt" + ], "description": "Agent identifier (replaces 'type' field in new format): 'awf' for Agent Workflow Firewall, 'srt' for Sandbox Runtime" }, "type": { "type": "string", - "enum": ["awf", "srt"], + "enum": [ + "awf", + "srt" + ], "description": "Legacy: Sandbox type to use (use 'id' instead)" }, "command": { @@ -2260,7 +2710,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", @@ -2375,14 +2830,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", @@ -2406,7 +2871,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", @@ -2431,11 +2901,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 } }, @@ -2456,7 +2931,10 @@ "type": "srt", "config": { "filesystem": { - "allowWrite": [".", "/tmp"] + "allowWrite": [ + ".", + "/tmp" + ] } } } @@ -2478,9 +2956,12 @@ ] }, "plugins": { - "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.", + "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.", "examples": [ - ["github/copilot-plugin", "acme/custom-tools"], + [ + "github/copilot-plugin", + "acme/custom-tools" + ], [ "github/simple-plugin", { @@ -2493,7 +2974,10 @@ } ], { - "repos": ["github/copilot-plugin", "acme/custom-tools"], + "repos": [ + "github/copilot-plugin", + "acme/custom-tools" + ], "github-token": "${{ secrets.CUSTOM_PLUGIN_TOKEN }}" } ], @@ -2511,7 +2995,9 @@ { "type": "object", "description": "Plugin configuration with ID and optional MCP settings for environment variables", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string", @@ -2547,7 +3033,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", @@ -2562,7 +3050,9 @@ { "type": "object", "description": "Plugin configuration with ID and optional MCP settings", - "required": ["id"], + "required": [ + "id" + ], "properties": { "id": { "type": "string", @@ -2592,7 +3082,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 @@ -2602,7 +3094,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", @@ -2675,7 +3170,7 @@ [ { "name": "Verify Post-Steps Execution", - "run": "echo \"āœ… Post-steps are executing correctly\"\necho \"This step runs after the AI agent completes\"\n" + "run": "echo \"\u2705 Post-steps are executing correctly\"\necho \"This step runs after the AI agent completes\"\n" }, { "name": "Upload Test Results", @@ -2720,7 +3215,10 @@ "filesystem": { "type": "stdio", "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-filesystem"] + "args": [ + "-y", + "@modelcontextprotocol/server-filesystem" + ] } }, { @@ -2797,13 +3295,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", @@ -2868,7 +3377,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", @@ -2894,7 +3411,10 @@ } } }, - "required": ["app-id", "private-key"], + "required": [ + "app-id", + "private-key" + ], "additionalProperties": false, "examples": [ { @@ -2904,7 +3424,10 @@ { "app-id": "${{ vars.APP_ID }}", "private-key": "${{ secrets.APP_PRIVATE_KEY }}", - "repositories": ["repo1", "repo2"] + "repositories": [ + "repo1", + "repo2" + ] } ] } @@ -2912,16 +3435,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" + ] } ] } @@ -2929,14 +3466,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 ] @@ -2963,10 +3511,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": { @@ -3043,9 +3617,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.", @@ -3087,7 +3668,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", @@ -3124,7 +3708,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." }, @@ -3177,7 +3764,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." }, @@ -3189,7 +3779,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, @@ -3230,7 +3823,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", @@ -3249,7 +3846,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" + ] } }, { @@ -3257,14 +3861,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": { @@ -3288,7 +3902,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Go version (e.g., \"1.21\", 1.21)" }, "go-mod-file": { @@ -3315,7 +3932,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Node.js version for TypeScript (e.g., \"22\", 22)" } }, @@ -3334,7 +3954,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Python version (e.g., \"3.12\", 3.12)" } }, @@ -3353,7 +3976,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Java version (e.g., \"21\", 21)" } }, @@ -3372,7 +3998,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": "Rust version (e.g., \"stable\", \"1.75\")" } }, @@ -3391,7 +4020,10 @@ "type": "object", "properties": { "version": { - "type": ["string", "number"], + "type": [ + "string", + "number" + ], "description": ".NET version for C# (e.g., \"8.0\", 8.0)" } }, @@ -3637,11 +4269,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": { @@ -3678,7 +4318,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", @@ -3686,12 +4329,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", @@ -3700,7 +4359,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 @@ -3768,17 +4435,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 } @@ -3839,7 +4514,10 @@ "description": "If true, only checks if cache entry exists and skips download" } }, - "required": ["key", "path"], + "required": [ + "key", + "path" + ], "additionalProperties": false } } @@ -3853,13 +4531,18 @@ { "create-issue": { "title-prefix": "[AI] ", - "labels": ["automation", "ai-generated"] + "labels": [ + "automation", + "ai-generated" + ] } }, { "create-pull-request": { "title-prefix": "[Bot] ", - "labels": ["bot"] + "labels": [ + "bot" + ] } }, { @@ -3882,7 +4565,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": [ @@ -3955,7 +4650,9 @@ }, { "type": "boolean", - "enum": [false], + "enum": [ + false + ], "description": "Set to false to explicitly disable expiration" } ], @@ -3981,21 +4678,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 } ] @@ -4095,7 +4804,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", @@ -4111,7 +4822,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", @@ -4119,7 +4833,10 @@ "items": { "type": "object", "description": "View configuration for creating project views", - "required": ["name", "layout"], + "required": [ + "name", + "layout" + ], "properties": { "name": { "type": "string", @@ -4127,7 +4844,11 @@ }, "layout": { "type": "string", - "enum": ["table", "board", "roadmap"], + "enum": [ + "table", + "board", + "roadmap" + ], "description": "The layout type of the view" }, "filter": { @@ -4154,7 +4875,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", @@ -4162,7 +4886,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": { @@ -4225,7 +4955,10 @@ "items": { "type": "object", "description": "View configuration for creating project views", - "required": ["name", "layout"], + "required": [ + "name", + "layout" + ], "properties": { "name": { "type": "string", @@ -4233,7 +4966,11 @@ }, "layout": { "type": "string", - "enum": ["table", "board", "roadmap"], + "enum": [ + "table", + "board", + "roadmap" + ], "description": "The layout type of the view" }, "filter": { @@ -4260,7 +4997,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", @@ -4268,7 +5008,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": { @@ -4290,7 +5036,9 @@ "description": "Enable project creation with default configuration (max=1)" }, { - "enum": [null], + "enum": [ + null + ], "description": "Alternative null value syntax" } ], @@ -4304,7 +5052,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", @@ -4320,7 +5070,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, @@ -4352,9 +5105,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", @@ -4416,7 +5176,9 @@ }, { "type": "boolean", - "enum": [false], + "enum": [ + false + ], "description": "Set to false to explicitly disable expiration" } ], @@ -4443,12 +5205,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" } ] @@ -4502,7 +5269,10 @@ "required-category": "Ideas" }, { - "required-labels": ["resolved", "completed"], + "required-labels": [ + "resolved", + "completed" + ], "max": 1 } ] @@ -4613,7 +5383,10 @@ "required-title-prefix": "[refactor] " }, { - "required-labels": ["automated", "stale"], + "required-labels": [ + "automated", + "stale" + ], "max": 10 } ] @@ -4659,6 +5432,14 @@ "github-token": { "$ref": "#/$defs/github_token", "description": "GitHub token to use for this specific output type. Overrides global github-token if specified." + }, + "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 + ] } }, "additionalProperties": false, @@ -4667,7 +5448,10 @@ "required-title-prefix": "[bot] " }, { - "required-labels": ["automated", "outdated"], + "required-labels": [ + "automated", + "outdated" + ], "max": 5 } ] @@ -4721,7 +5505,10 @@ "required-title-prefix": "[bot] " }, { - "required-labels": ["automated", "ready"], + "required-labels": [ + "automated", + "ready" + ], "max": 1 } ] @@ -4775,7 +5562,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" + ] } } }, @@ -4844,7 +5637,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": { @@ -4905,13 +5702,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" } ] @@ -4938,7 +5741,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", @@ -5003,7 +5809,7 @@ "oneOf": [ { "type": "object", - "description": "Configuration for resolving review threads on pull requests. Resolution is scoped to the triggering PR only — threads on other PRs cannot be resolved.", + "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.", "properties": { "max": { "type": "integer", @@ -5277,7 +6083,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": { @@ -5322,7 +6131,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": { @@ -5362,7 +6174,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": { @@ -5461,7 +6276,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 }, @@ -5511,7 +6329,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", @@ -5568,7 +6390,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": { @@ -5578,6 +6404,14 @@ "github-token": { "$ref": "#/$defs/github_token", "description": "GitHub token to use for this specific output type. Overrides global github-token if specified." + }, + "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 + ] } }, "additionalProperties": false @@ -5610,7 +6444,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" + ] } } }, @@ -5647,7 +6487,9 @@ "description": "GitHub token to use for dispatching workflows. Overrides global github-token if specified." } }, - "required": ["workflows"], + "required": [ + "workflows" + ], "additionalProperties": false }, { @@ -5877,7 +6719,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", @@ -5893,7 +6738,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", @@ -5902,17 +6751,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", @@ -5920,10 +6777,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": { @@ -6081,7 +6949,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" }, @@ -6118,52 +6992,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: 'šŸŽ­ Preview: {operation}'", - "examples": ["šŸŽ­ Preview: {operation}", "## Staged Mode: {operation}"] + "description": "Custom title template for staged mode preview. Available placeholders: {operation}. Example: '\ud83c\udfad Preview: {operation}'", + "examples": [ + "\ud83c\udfad 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: 'āœ… Agentic [{workflow_name}]({run_url}) completed successfully.'", - "examples": ["āœ… Agentic [{workflow_name}]({run_url}) completed successfully.", "āœ… [{workflow_name}]({run_url}) finished."] + "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." + ] }, "run-failure": { "type": "string", - "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}."] + "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}." + ] }, "detection-failure": { "type": "string", - "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})."] + "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})." + ] }, "append-only-comments": { "type": "boolean", @@ -6217,7 +7120,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", @@ -6249,19 +7155,27 @@ "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).", + "description": "Repository access roles required to trigger agentic workflows. Defaults to ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any authenticated user (\u26a0\ufe0f security consideration).", "oneOf": [ { "type": "string", - "enum": ["all"], - "description": "Allow any authenticated user to trigger the workflow (āš ļø disables permission checking entirely - use with caution)" + "enum": [ + "all" + ], + "description": "Allow any authenticated user to trigger the workflow (\u26a0\ufe0f 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"], + "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, @@ -6281,7 +7195,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", @@ -6301,7 +7217,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 }, @@ -6310,7 +7235,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 } @@ -6324,12 +7255,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" + ] } ] }, @@ -6338,7 +7275,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", @@ -6347,7 +7287,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", @@ -6361,7 +7303,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." }, @@ -6415,71 +7363,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" + ] } ] } @@ -6537,9 +7522,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", @@ -6576,7 +7570,9 @@ } } }, - "required": ["slash_command"] + "required": [ + "slash_command" + ] }, { "properties": { @@ -6586,7 +7582,9 @@ } } }, - "required": ["command"] + "required": [ + "command" + ] } ] } @@ -6605,7 +7603,9 @@ } } }, - "required": ["issue_comment"] + "required": [ + "issue_comment" + ] }, { "properties": { @@ -6615,7 +7615,9 @@ } } }, - "required": ["pull_request_review_comment"] + "required": [ + "pull_request_review_comment" + ] }, { "properties": { @@ -6625,7 +7627,9 @@ } } }, - "required": ["label"] + "required": [ + "label" + ] } ] } @@ -6659,7 +7663,12 @@ "oneOf": [ { "type": "string", - "enum": ["claude", "codex", "copilot", "custom"], + "enum": [ + "claude", + "codex", + "copilot", + "custom" + ], "description": "Simple engine name: 'claude' (default, Claude Code), 'copilot' (GitHub Copilot CLI), 'codex' (OpenAI Codex CLI), or 'custom' (user-defined steps)" }, { @@ -6668,13 +7677,26 @@ "properties": { "id": { "type": "string", - "enum": ["claude", "codex", "custom", "copilot"], + "enum": [ + "claude", + "codex", + "custom", + "copilot" + ], "description": "AI engine identifier: 'claude' (Claude Code), 'codex' (OpenAI Codex CLI), 'copilot' (GitHub Copilot CLI), or 'custom' (user-defined GitHub Actions steps)" }, "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", @@ -6712,7 +7734,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 } ], @@ -6771,7 +7795,9 @@ "description": "Human-readable description of what this pattern matches" } }, - "required": ["pattern"], + "required": [ + "pattern" + ], "additionalProperties": false } }, @@ -6791,7 +7817,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 } ] @@ -6802,13 +7830,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", @@ -6823,9 +7856,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", @@ -6837,7 +7878,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", @@ -6853,7 +7898,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", @@ -6899,29 +7952,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" + ] } ] }, @@ -6930,17 +8004,24 @@ "if": { "properties": { "type": { - "enum": ["stdio", "local"] + "enum": [ + "stdio", + "local" + ] } } }, "then": { "anyOf": [ { - "required": ["command"] + "required": [ + "command" + ] }, { - "required": ["container"] + "required": [ + "container" + ] } ] } @@ -6953,13 +8034,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", @@ -6982,17 +8067,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", @@ -7053,12 +8155,16 @@ "additionalProperties": false, "anyOf": [ { - "required": ["uses"] + "required": [ + "uses" + ] }, { - "required": ["run"] + "required": [ + "run" + ] } ] } } -} +} \ No newline at end of file diff --git a/pkg/workflow/compiler_types.go b/pkg/workflow/compiler_types.go index f97f23e1bf..5cbf58915d 100644 --- a/pkg/workflow/compiler_types.go +++ b/pkg/workflow/compiler_types.go @@ -454,6 +454,7 @@ type WorkflowData struct { type BaseSafeOutputConfig struct { Max int `yaml:"max,omitempty"` // Maximum number of items to create GitHubToken string `yaml:"github-token,omitempty"` // GitHub token for this specific output type + Staged bool `yaml:"staged,omitempty"` // If true, emit step summary messages instead of making GitHub API calls for this specific output type } // SafeOutputsConfig holds configuration for automatic output routes