From 5f2440855ebcb430555ab1dd21bbf7ef0ab6f7aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Aug 2026 03:55:27 +0000 Subject: [PATCH 1/5] Initial plan From a273bd02475853699b8130d33f8729fdd43f587f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Aug 2026 04:08:06 +0000 Subject: [PATCH 2/5] refactor: share GitHub MCP renderer option fields Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/engine_helpers_github_test.go | 56 ++++++++++++------- pkg/workflow/github_lockdown_test.go | 60 ++++++++++++-------- pkg/workflow/github_remote_config_test.go | 64 ++++++++++++++-------- pkg/workflow/mcp_renderer_github.go | 52 ++++++++++-------- pkg/workflow/mcp_renderer_types.go | 38 +++++-------- pkg/workflow/mcp_renderer_types_test.go | 30 ++++++++++ 6 files changed, 182 insertions(+), 118 deletions(-) create mode 100644 pkg/workflow/mcp_renderer_types_test.go diff --git a/pkg/workflow/engine_helpers_github_test.go b/pkg/workflow/engine_helpers_github_test.go index cbeb2bae49e..e6ca95ae59b 100644 --- a/pkg/workflow/engine_helpers_github_test.go +++ b/pkg/workflow/engine_helpers_github_test.go @@ -17,12 +17,14 @@ func TestRenderGitHubMCPDockerConfig(t *testing.T) { { name: "Claude engine configuration (no type field, with effective token)", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: nil, + }, DockerImageVersion: "latest", CustomArgs: nil, IncludeTypeField: false, - AllowedTools: nil, EffectiveToken: "${{ secrets.GITHUB_TOKEN }}", }, expected: []string{ @@ -42,12 +44,14 @@ func TestRenderGitHubMCPDockerConfig(t *testing.T) { { name: "Copilot engine configuration (with type field, no effective token)", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: []string{"create_issue", "issue_read"}, + }, DockerImageVersion: "latest", CustomArgs: nil, IncludeTypeField: true, - AllowedTools: []string{"create_issue", "issue_read"}, EffectiveToken: "", }, expected: []string{ @@ -67,12 +71,14 @@ func TestRenderGitHubMCPDockerConfig(t *testing.T) { { name: "Read-only mode enabled", options: GitHubMCPDockerOptions{ - ReadOnly: true, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Toolsets: "default", + AllowedTools: nil, + }, DockerImageVersion: "v1.0.0", CustomArgs: nil, IncludeTypeField: false, - AllowedTools: nil, EffectiveToken: "", }, expected: []string{ @@ -90,12 +96,14 @@ func TestRenderGitHubMCPDockerConfig(t *testing.T) { { name: "Custom args provided", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: nil, + }, DockerImageVersion: "latest", CustomArgs: []string{"--verbose", "--debug"}, IncludeTypeField: false, - AllowedTools: nil, EffectiveToken: "", }, expected: []string{ @@ -111,12 +119,14 @@ func TestRenderGitHubMCPDockerConfig(t *testing.T) { { name: "Copilot with wildcard tools (no allowed tools specified)", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: nil, // When nil, should default to wildcard + }, DockerImageVersion: "latest", CustomArgs: nil, IncludeTypeField: true, - AllowedTools: nil, // When nil, should default to wildcard EffectiveToken: "", }, expected: []string{ @@ -131,12 +141,14 @@ func TestRenderGitHubMCPDockerConfig(t *testing.T) { { name: "Custom toolsets", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Toolsets: "repos,issues,pull_requests", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "repos,issues,pull_requests", + AllowedTools: nil, + }, DockerImageVersion: "latest", CustomArgs: nil, IncludeTypeField: false, - AllowedTools: nil, EffectiveToken: "", }, expected: []string{ @@ -176,12 +188,14 @@ func TestRenderGitHubMCPDockerConfig_OutputStructure(t *testing.T) { // Test that the output has the expected JSON structure var yaml strings.Builder RenderGitHubMCPDockerConfig(&yaml, GitHubMCPDockerOptions{ - ReadOnly: true, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Toolsets: "default", + AllowedTools: []string{"tool1", "tool2"}, + }, DockerImageVersion: "latest", CustomArgs: []string{"--test"}, IncludeTypeField: true, - AllowedTools: []string{"tool1", "tool2"}, EffectiveToken: "", }) diff --git a/pkg/workflow/github_lockdown_test.go b/pkg/workflow/github_lockdown_test.go index 2c35fe8f246..01598f9f89e 100644 --- a/pkg/workflow/github_lockdown_test.go +++ b/pkg/workflow/github_lockdown_test.go @@ -114,12 +114,14 @@ func TestRenderGitHubMCPDockerConfigWithLockdown(t *testing.T) { { name: "Docker mode with lockdown enabled", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Lockdown: true, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Lockdown: true, + Toolsets: "default", + AllowedTools: nil, + }, DockerImageVersion: "latest", IncludeTypeField: true, - AllowedTools: nil, }, expected: []string{ `"type": "stdio"`, @@ -132,12 +134,14 @@ func TestRenderGitHubMCPDockerConfigWithLockdown(t *testing.T) { { name: "Docker mode with lockdown disabled", options: GitHubMCPDockerOptions{ - ReadOnly: false, - Lockdown: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Lockdown: false, + Toolsets: "default", + AllowedTools: nil, + }, DockerImageVersion: "latest", IncludeTypeField: true, - AllowedTools: nil, }, expected: []string{ `"type": "stdio"`, @@ -151,12 +155,14 @@ func TestRenderGitHubMCPDockerConfigWithLockdown(t *testing.T) { { name: "Docker mode with lockdown and read-only both enabled", options: GitHubMCPDockerOptions{ - ReadOnly: true, - Lockdown: true, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Lockdown: true, + Toolsets: "default", + AllowedTools: nil, + }, DockerImageVersion: "v1.0.0", IncludeTypeField: false, - AllowedTools: nil, }, expected: []string{ `"GITHUB_READ_ONLY": "1"`, @@ -200,12 +206,14 @@ func TestRenderGitHubMCPRemoteConfigWithLockdown(t *testing.T) { { name: "Remote mode with lockdown enabled", options: GitHubMCPRemoteOptions{ - ReadOnly: false, - Lockdown: true, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Lockdown: true, + Toolsets: "default", + AllowedTools: []string{"*"}, + }, AuthorizationValue: "Bearer test-token", IncludeToolsField: true, - AllowedTools: []string{"*"}, IncludeEnvSection: false, }, expected: []string{ @@ -221,12 +229,14 @@ func TestRenderGitHubMCPRemoteConfigWithLockdown(t *testing.T) { { name: "Remote mode with lockdown disabled", options: GitHubMCPRemoteOptions{ - ReadOnly: false, - Lockdown: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Lockdown: false, + Toolsets: "default", + AllowedTools: []string{"*"}, + }, AuthorizationValue: "Bearer test-token", IncludeToolsField: true, - AllowedTools: []string{"*"}, IncludeEnvSection: false, }, expected: []string{ @@ -242,12 +252,14 @@ func TestRenderGitHubMCPRemoteConfigWithLockdown(t *testing.T) { { name: "Remote mode with lockdown and read-only both enabled", options: GitHubMCPRemoteOptions{ - ReadOnly: true, - Lockdown: true, - Toolsets: "repos,issues", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Lockdown: true, + Toolsets: "repos,issues", + AllowedTools: nil, + }, AuthorizationValue: "Bearer test-token", IncludeToolsField: false, - AllowedTools: nil, IncludeEnvSection: false, }, expected: []string{ diff --git a/pkg/workflow/github_remote_config_test.go b/pkg/workflow/github_remote_config_test.go index fc396deaed3..e446248ddac 100644 --- a/pkg/workflow/github_remote_config_test.go +++ b/pkg/workflow/github_remote_config_test.go @@ -17,11 +17,13 @@ func TestRenderGitHubMCPRemoteConfig(t *testing.T) { { name: "Claude-style config without tools or env", options: GitHubMCPRemoteOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: nil, + }, AuthorizationValue: "Bearer ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", IncludeToolsField: false, - AllowedTools: nil, IncludeEnvSection: false, }, expectedOutput: []string{ @@ -40,11 +42,13 @@ func TestRenderGitHubMCPRemoteConfig(t *testing.T) { { name: "Claude-style config with read-only", options: GitHubMCPRemoteOptions{ - ReadOnly: true, - Toolsets: "repos,issues", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Toolsets: "repos,issues", + AllowedTools: nil, + }, AuthorizationValue: "Bearer ${{ secrets.CUSTOM_PAT }}", IncludeToolsField: false, - AllowedTools: nil, IncludeEnvSection: false, }, expectedOutput: []string{ @@ -63,11 +67,13 @@ func TestRenderGitHubMCPRemoteConfig(t *testing.T) { { name: "Copilot-style config with tools and env", options: GitHubMCPRemoteOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: []string{"list_issues", "create_issue"}, + }, AuthorizationValue: "Bearer \\${GITHUB_PERSONAL_ACCESS_TOKEN}", IncludeToolsField: true, - AllowedTools: []string{"list_issues", "create_issue"}, IncludeEnvSection: true, }, expectedOutput: []string{ @@ -92,11 +98,13 @@ func TestRenderGitHubMCPRemoteConfig(t *testing.T) { { name: "Copilot-style config with wildcard tools", options: GitHubMCPRemoteOptions{ - ReadOnly: false, - Toolsets: "all", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "all", + AllowedTools: nil, // Empty array should result in wildcard + }, AuthorizationValue: "Bearer \\${GITHUB_PERSONAL_ACCESS_TOKEN}", IncludeToolsField: true, - AllowedTools: nil, // Empty array should result in wildcard IncludeEnvSection: true, }, expectedOutput: []string{ @@ -117,11 +125,13 @@ func TestRenderGitHubMCPRemoteConfig(t *testing.T) { { name: "Copilot-style config with read-only and specific tools", options: GitHubMCPRemoteOptions{ - ReadOnly: true, - Toolsets: "repos", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Toolsets: "repos", + AllowedTools: []string{"list_repositories", "get_repository"}, + }, AuthorizationValue: "Bearer \\${GITHUB_PERSONAL_ACCESS_TOKEN}", IncludeToolsField: true, - AllowedTools: []string{"list_repositories", "get_repository"}, IncludeEnvSection: true, }, expectedOutput: []string{ @@ -145,11 +155,13 @@ func TestRenderGitHubMCPRemoteConfig(t *testing.T) { { name: "No toolsets configured", options: GitHubMCPRemoteOptions{ - ReadOnly: false, - Toolsets: "", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "", + AllowedTools: nil, + }, AuthorizationValue: "Bearer ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", IncludeToolsField: false, - AllowedTools: nil, IncludeEnvSection: false, }, expectedOutput: []string{ @@ -194,11 +206,13 @@ func TestRenderGitHubMCPRemoteConfigHeaderOrder(t *testing.T) { // Test that headers are sorted alphabetically for deterministic output var yaml strings.Builder RenderGitHubMCPRemoteConfig(&yaml, GitHubMCPRemoteOptions{ - ReadOnly: true, - Toolsets: "repos,issues", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: true, + Toolsets: "repos,issues", + AllowedTools: nil, + }, AuthorizationValue: "Bearer token", IncludeToolsField: false, - AllowedTools: nil, IncludeEnvSection: false, }) output := yaml.String() @@ -225,11 +239,13 @@ func TestRenderGitHubMCPRemoteConfigToolsCommas(t *testing.T) { // Test that tools array is properly formatted with commas var yaml strings.Builder RenderGitHubMCPRemoteConfig(&yaml, GitHubMCPRemoteOptions{ - ReadOnly: false, - Toolsets: "default", + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: false, + Toolsets: "default", + AllowedTools: []string{"tool1", "tool2", "tool3"}, + }, AuthorizationValue: "Bearer token", IncludeToolsField: true, - AllowedTools: []string{"tool1", "tool2", "tool3"}, IncludeEnvSection: true, }) output := yaml.String() diff --git a/pkg/workflow/mcp_renderer_github.go b/pkg/workflow/mcp_renderer_github.go index 556a048bba6..2ba310ce374 100644 --- a/pkg/workflow/mcp_renderer_github.go +++ b/pkg/workflow/mcp_renderer_github.go @@ -66,17 +66,19 @@ func (r *MCPConfigRendererUnified) RenderGitHubMCP(yaml *strings.Builder, github } RenderGitHubMCPRemoteConfig(yaml, GitHubMCPRemoteOptions{ - ReadOnly: readOnly, - Lockdown: lockdown, - LockdownFromStep: false, - GuardPoliciesFromStep: shouldUseStepOutputForGuardPolicy, - Toolsets: toolsets, - Features: features, - AuthorizationValue: authValue, - IncludeToolsField: r.options.IncludeCopilotFields, - AllowedTools: getGitHubAllowedTools(githubTool), - IncludeEnvSection: r.options.IncludeCopilotFields, - GuardPolicies: explicitGuardPolicies, + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: readOnly, + Lockdown: lockdown, + LockdownFromStep: false, + GuardPoliciesFromStep: shouldUseStepOutputForGuardPolicy, + Toolsets: toolsets, + Features: features, + AllowedTools: getGitHubAllowedTools(githubTool), + GuardPolicies: explicitGuardPolicies, + }, + AuthorizationValue: authValue, + IncludeToolsField: r.options.IncludeCopilotFields, + IncludeEnvSection: r.options.IncludeCopilotFields, }) } else { // Local mode - use Docker-based GitHub MCP server (default) @@ -86,19 +88,21 @@ func (r *MCPConfigRendererUnified) RenderGitHubMCP(yaml *strings.Builder, github mcpRendererLog.Printf("GitHub MCP local docker mode: image_version=%s, custom_args=%d", githubDockerImageVersion, len(customArgs)) RenderGitHubMCPDockerConfig(yaml, GitHubMCPDockerOptions{ - ReadOnly: readOnly, - Lockdown: lockdown, - LockdownFromStep: false, - GuardPoliciesFromStep: shouldUseStepOutputForGuardPolicy, - Toolsets: toolsets, - Features: features, - DockerImageVersion: githubDockerImageVersion, - CustomArgs: customArgs, - IncludeTypeField: r.options.IncludeCopilotFields, - AllowedTools: getGitHubAllowedTools(githubTool), - EffectiveToken: "", // Token passed via env - GuardPolicies: explicitGuardPolicies, - ContainerPinMappings: r.options.ContainerPinMappings, + GitHubMCPCommonOptions: GitHubMCPCommonOptions{ + ReadOnly: readOnly, + Lockdown: lockdown, + LockdownFromStep: false, + GuardPoliciesFromStep: shouldUseStepOutputForGuardPolicy, + Toolsets: toolsets, + Features: features, + AllowedTools: getGitHubAllowedTools(githubTool), + GuardPolicies: explicitGuardPolicies, + }, + DockerImageVersion: githubDockerImageVersion, + CustomArgs: customArgs, + IncludeTypeField: r.options.IncludeCopilotFields, + EffectiveToken: "", // Token passed via env + ContainerPinMappings: r.options.ContainerPinMappings, }) } diff --git a/pkg/workflow/mcp_renderer_types.go b/pkg/workflow/mcp_renderer_types.go index a56848bc8f3..1c3f8810d15 100644 --- a/pkg/workflow/mcp_renderer_types.go +++ b/pkg/workflow/mcp_renderer_types.go @@ -63,8 +63,8 @@ type JSONMCPConfigOptions struct { GatewayConfig *MCPGatewayRuntimeConfig } -// GitHubMCPDockerOptions defines configuration for GitHub MCP Docker rendering -type GitHubMCPDockerOptions struct { +// GitHubMCPCommonOptions defines shared configuration for GitHub MCP rendering. +type GitHubMCPCommonOptions struct { // ReadOnly enables read-only mode for GitHub API operations ReadOnly bool // Lockdown enables lockdown mode for GitHub MCP server (limits content from public repos) @@ -77,20 +77,25 @@ type GitHubMCPDockerOptions struct { // Toolsets specifies the GitHub toolsets to enable Toolsets string // Features is a comma-separated list of GitHub MCP feature flags to enable (e.g. "fields_param"). - // Emitted as GITHUB_FEATURES env var for the Docker container. + // Emitted as GITHUB_FEATURES env var for Docker or X-MCP-Features header for remote mode. Features string + // AllowedTools specifies the list of allowed tools (Copilot uses this, Claude doesn't) + AllowedTools []string + // GuardPolicies specifies access control policies for the MCP gateway (e.g., allow-only repos/integrity) + GuardPolicies map[string]any +} + +// GitHubMCPDockerOptions defines configuration for GitHub MCP Docker rendering +type GitHubMCPDockerOptions struct { + GitHubMCPCommonOptions // DockerImageVersion specifies the GitHub MCP server Docker image version DockerImageVersion string // CustomArgs are additional arguments to append to the Docker command CustomArgs []string // IncludeTypeField indicates whether to include the "type": "stdio" field (Copilot needs it, Claude doesn't) IncludeTypeField bool - // AllowedTools specifies the list of allowed tools (Copilot uses this, Claude doesn't) - AllowedTools []string // EffectiveToken is the GitHub token to use (Claude uses this, Copilot uses env passthrough) EffectiveToken string - // GuardPolicies specifies access control policies for the MCP gateway (e.g., allow-only repos/integrity) - GuardPolicies map[string]any // ContainerPinMappings maps source container image references to their SHA-pinned replacements. // When set, the GitHub MCP server container reference is redirected to the mapped private // registry mirror (digest stripped for MCP Gateway compatibility). Nil → no redirect. @@ -99,30 +104,13 @@ type GitHubMCPDockerOptions struct { // GitHubMCPRemoteOptions defines configuration for GitHub MCP remote mode rendering type GitHubMCPRemoteOptions struct { - // ReadOnly enables read-only mode for GitHub API operations - ReadOnly bool - // Lockdown enables lockdown mode for GitHub MCP server (limits content from public repos) - Lockdown bool - // LockdownFromStep indicates if lockdown value should be read from step output - LockdownFromStep bool - // GuardPoliciesFromStep indicates if guard policy values should be read from step outputs - // (GITHUB_MCP_GUARD_MIN_INTEGRITY and GITHUB_MCP_GUARD_REPOS env vars) - GuardPoliciesFromStep bool - // Toolsets specifies the GitHub toolsets to enable - Toolsets string - // Features is a comma-separated list of GitHub MCP feature flags to enable (e.g. "fields_param"). - // Emitted as X-MCP-Features header for the hosted endpoint. - Features string + GitHubMCPCommonOptions // AuthorizationValue is the value for the Authorization header // For Claude: "Bearer {effectiveToken}" // For Copilot: "Bearer \\${GITHUB_PERSONAL_ACCESS_TOKEN}" AuthorizationValue string // IncludeToolsField indicates whether to include the "tools" field (Copilot needs it, Claude doesn't) IncludeToolsField bool - // AllowedTools specifies the list of allowed tools (Copilot uses this, Claude doesn't) - AllowedTools []string // IncludeEnvSection indicates whether to include the env section (Copilot needs it, Claude doesn't) IncludeEnvSection bool - // GuardPolicies specifies access control policies for the MCP gateway (e.g., allow-only repos/integrity) - GuardPolicies map[string]any } diff --git a/pkg/workflow/mcp_renderer_types_test.go b/pkg/workflow/mcp_renderer_types_test.go new file mode 100644 index 00000000000..f17757488b4 --- /dev/null +++ b/pkg/workflow/mcp_renderer_types_test.go @@ -0,0 +1,30 @@ +//go:build !integration + +package workflow + +import ( + "reflect" + "testing" +) + +func TestGitHubMCPOptionsEmbedCommonOptions(t *testing.T) { + tests := []struct { + name string + optionType reflect.Type + }{ + {name: "docker", optionType: reflect.TypeOf(GitHubMCPDockerOptions{})}, + {name: "remote", optionType: reflect.TypeOf(GitHubMCPRemoteOptions{})}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + field, ok := tt.optionType.FieldByName("GitHubMCPCommonOptions") + if !ok { + t.Fatalf("expected %s to embed GitHubMCPCommonOptions", tt.optionType.Name()) + } + if !field.Anonymous { + t.Fatalf("expected %s.GitHubMCPCommonOptions to be embedded", tt.optionType.Name()) + } + }) + } +} From be1a68acc5ae10e0dcec65ad3e06462aa951ac8d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:14:22 +0000 Subject: [PATCH 3/5] docs(adr): add draft ADR-54714 for shared GitHub MCP common options struct --- ...-mcp-common-options-via-embedded-struct.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/adr/54714-share-github-mcp-common-options-via-embedded-struct.md diff --git a/docs/adr/54714-share-github-mcp-common-options-via-embedded-struct.md b/docs/adr/54714-share-github-mcp-common-options-via-embedded-struct.md new file mode 100644 index 00000000000..246b7da9339 --- /dev/null +++ b/docs/adr/54714-share-github-mcp-common-options-via-embedded-struct.md @@ -0,0 +1,44 @@ +# ADR-54714: Share GitHub MCP Common Options via Embedded Struct + +**Date**: 2026-08-22 +**Status**: Draft +**Deciders**: pelikhan, copilot-swe-agent + +--- + +### Context + +The GitHub MCP renderer supports two transport modes — Docker (local) and Remote (hosted). Each mode has its own configuration struct (`GitHubMCPDockerOptions` and `GitHubMCPRemoteOptions`). Both structs independently declared the same 8 fields: `ReadOnly`, `Lockdown`, `LockdownFromStep`, `GuardPoliciesFromStep`, `Toolsets`, `Features`, `AllowedTools`, and `GuardPolicies`. These fields control shared MCP behaviour (read-only access, lockdown enforcement, guard policies, toolset selection, feature flags, and allowed-tool filtering) regardless of transport. The duplication meant that any change to shared behaviour required coordinated edits in two places, with no compiler-level guarantee that the structs remained in sync, creating ongoing drift risk. + +### Decision + +We will introduce `GitHubMCPCommonOptions` as a new shared struct containing all 8 transport-agnostic fields, and update `GitHubMCPDockerOptions` and `GitHubMCPRemoteOptions` to embed it anonymously. A regression test (`TestGitHubMCPOptionsEmbedCommonOptions`) uses reflection to assert that both transport structs embed `GitHubMCPCommonOptions`, enforcing the constraint at compile/test time. All construction sites in `mcp_renderer_github.go` initialise shared fields via the embedded struct literal. + +### Alternatives Considered + +#### Alternative 1: Keep duplicated fields (status quo) + +Each transport struct retains its own independent copy of the 8 shared fields. Behaviour is identical to the new approach at runtime. Rejected because: there is no mechanism to prevent the structs from diverging independently — the problem that motivated this PR — and future changes to shared fields must always be made twice with no compiler enforcement. + +#### Alternative 2: Shared builder function instead of struct embedding + +A helper function (e.g., `newCommonOptions(...)`) could accept the common arguments and populate each transport struct's fields individually. This avoids anonymous embedding and keeps field access flat. Rejected because: it does not create a named type boundary visible in struct literals, making it harder to see at a glance which fields are shared; and it provides no compile-time or test-time guarantee that both transport structs expose the same set of shared fields. + +### Consequences + +#### Positive +- Single definition for all shared GitHub MCP configuration fields; any new shared field is added once. +- Compile/test-time enforcement via `TestGitHubMCPOptionsEmbedCommonOptions` prevents future structs from silently omitting the embedded type. +- Reduced field count in transport-specific structs; transport-specific fields are clearly distinguished from shared ones. + +#### Negative +- Call sites must use the explicit embedded struct key (`GitHubMCPCommonOptions: GitHubMCPCommonOptions{...}`) in keyed struct literals, which is more verbose than flat field assignment. +- Go's field promotion means shared fields appear on the transport struct's surface, which can obscure their origin for readers unfamiliar with the embedding relationship. + +#### Neutral +- All existing test cases required mechanical updates to use the embedded struct literal syntax — no test logic changed, only struct initialisation syntax. +- The regression test uses `reflect.Type.FieldByName` + `Anonymous` check, which is a non-zero dependency on reflection in the test suite. + +--- + +*ADR created by [adr-writer agent]. Review and finalize before changing status from Draft to Accepted.* From 077fd8758506378594726118b92d96b19ff9040c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:50:29 +0000 Subject: [PATCH 4/5] Plan: investigate failing lint-go-golangci and address PR bot feedback Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- .github/workflows/agentic_commands.yml | 7 +++---- pkg/workflow/schemas/github-workflow.json | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/agentic_commands.yml b/.github/workflows/agentic_commands.yml index e9f5699b47d..dbb43b5ca6a 100644 --- a/.github/workflows/agentic_commands.yml +++ b/.github/workflows/agentic_commands.yml @@ -1,4 +1,4 @@ -# gh-aw-commands: {"payload_version":"v1","schema_version":"v1","compiler_version":"dev","commands":["*","ace","approach-validator","archie","cloclo","craft","dependabot-burner","grumpy","matt","mergefest","nit","plan","poem-bot","ponytail","review","ruflo","scout","security-review","smoke-agent-all-merged","smoke-agent-all-none","smoke-agent-public-approved","smoke-agent-public-none","smoke-agent-scoped-approved","smoke-aider","smoke-call-workflow","smoke-checkout-pr-dispatch","smoke-claude","smoke-claude-on-copilot","smoke-codex","smoke-copilot","smoke-copilot-aoai-apikey","smoke-copilot-aoai-entra","smoke-copilot-arm","smoke-copilot-mai","smoke-copilot-sdk","smoke-copilot-small","smoke-create-cross-repo-pr","smoke-crush","smoke-cursor","smoke-deepseek-harness","smoke-drive","smoke-gemini","smoke-github-claude","smoke-goose","smoke-kiro","smoke-multi-pr","smoke-opencode","smoke-otel-backends","smoke-pi","smoke-project","smoke-pydantic","smoke-service-ports","smoke-temporary-id","smoke-test-tools","smoke-update-cross-repo-pr","souschef","squad-plan","summarize","tidy","unbloat"],"workflows":["ace-editor","approach-validator","archie","ci-doctor","cloclo","craft","dependabot-burner","design-decision-gate","dev","grumpy-reviewer","mattpocock-skills-reviewer","mergefest","necromancer","pdf-summary","plan","poem-bot","ponytail-reviewer","pr-code-quality-reviewer","pr-nitpick-reviewer","pr-sous-chef","ruflo-backed-task","scout","security-review","skillet","smoke-agent-all-merged","smoke-agent-all-none","smoke-agent-public-approved","smoke-agent-public-none","smoke-agent-scoped-approved","smoke-aider","smoke-call-workflow","smoke-checkout-pr-dispatch","smoke-claude","smoke-claude-on-copilot","smoke-codex","smoke-copilot","smoke-copilot-aoai-apikey","smoke-copilot-aoai-entra","smoke-copilot-arm","smoke-copilot-mai","smoke-copilot-sdk","smoke-copilot-small","smoke-create-cross-repo-pr","smoke-crush","smoke-cursor","smoke-deepseek-harness","smoke-drive","smoke-gemini","smoke-github-claude","smoke-goose","smoke-kiro","smoke-multi-pr","smoke-opencode","smoke-otel-backends","smoke-pi","smoke-project","smoke-pydantic","smoke-service-ports","smoke-temporary-id","smoke-test-tools","smoke-update-cross-repo-pr","squad-plan","test-quality-sentinel","tidy","unbloat-docs"]} +# gh-aw-commands: {"payload_version":"v1","schema_version":"v1","compiler_version":"dev","commands":["*","ace","approach-validator","archie","cloclo","craft","dependabot-burner","grumpy","matt","mergefest","nit","plan","poem-bot","ponytail","review","ruflo","scout","security-review","smoke-agent-all-merged","smoke-agent-all-none","smoke-agent-public-approved","smoke-agent-public-none","smoke-agent-scoped-approved","smoke-aider","smoke-call-workflow","smoke-checkout-pr-dispatch","smoke-claude","smoke-claude-on-copilot","smoke-codex","smoke-copilot","smoke-copilot-aoai-apikey","smoke-copilot-aoai-entra","smoke-copilot-arm","smoke-copilot-mai","smoke-copilot-sdk","smoke-copilot-small","smoke-create-cross-repo-pr","smoke-crush","smoke-cursor","smoke-deepseek-harness","smoke-gemini","smoke-github-claude","smoke-goose","smoke-kiro","smoke-multi-pr","smoke-opencode","smoke-otel-backends","smoke-pi","smoke-project","smoke-pydantic","smoke-service-ports","smoke-temporary-id","smoke-test-tools","smoke-update-cross-repo-pr","souschef","squad-plan","summarize","tidy","unbloat"],"workflows":["ace-editor","approach-validator","archie","ci-doctor","cloclo","craft","dependabot-burner","design-decision-gate","dev","grumpy-reviewer","mattpocock-skills-reviewer","mergefest","necromancer","pdf-summary","plan","poem-bot","ponytail-reviewer","pr-code-quality-reviewer","pr-nitpick-reviewer","pr-sous-chef","ruflo-backed-task","scout","security-review","skillet","smoke-agent-all-merged","smoke-agent-all-none","smoke-agent-public-approved","smoke-agent-public-none","smoke-agent-scoped-approved","smoke-aider","smoke-call-workflow","smoke-checkout-pr-dispatch","smoke-claude","smoke-claude-on-copilot","smoke-codex","smoke-copilot","smoke-copilot-aoai-apikey","smoke-copilot-aoai-entra","smoke-copilot-arm","smoke-copilot-mai","smoke-copilot-sdk","smoke-copilot-small","smoke-create-cross-repo-pr","smoke-crush","smoke-cursor","smoke-deepseek-harness","smoke-gemini","smoke-github-claude","smoke-goose","smoke-kiro","smoke-multi-pr","smoke-opencode","smoke-otel-backends","smoke-pi","smoke-project","smoke-pydantic","smoke-service-ports","smoke-temporary-id","smoke-test-tools","smoke-update-cross-repo-pr","squad-plan","test-quality-sentinel","tidy","unbloat-docs"]} # Routing summary (sorted): # slash commands: # /* -> skillet [pull_request_comment,pull_request_review_comment] reaction=eyes @@ -43,7 +43,6 @@ # /smoke-crush -> smoke-crush [issue_comment,issues,pull_request,pull_request_comment] reaction=eyes # /smoke-cursor -> smoke-cursor [issue_comment,issues,pull_request,pull_request_comment] reaction=rocket # /smoke-deepseek-harness -> smoke-deepseek-harness [issue_comment,issues,pull_request,pull_request_comment] reaction=eyes -# /smoke-drive -> smoke-drive [issue_comment,issues,pull_request,pull_request_comment] reaction=rocket # /smoke-gemini -> smoke-gemini [issue_comment,issues,pull_request,pull_request_comment] reaction=rocket # /smoke-github-claude -> smoke-github-claude [pull_request,pull_request_comment] reaction=eyes # /smoke-goose -> smoke-goose [issue_comment,issues,pull_request,pull_request_comment] reaction=rocket @@ -142,9 +141,9 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 # runner-guard:ignore RGS-016 -- routing tables below contain emoji variation selectors (U+FE0F) and zero-width joiners (U+200D) used to render standard emoji sequences, not steganographic payloads. env: - GH_AW_SLASH_ROUTING: '{"*":[{"workflow":"skillet","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🍳","status_comment":true}],"ace":[{"workflow":"ace-editor","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"✏️","status_comment":true}],"approach-validator":[{"workflow":"approach-validator","events":["issue_comment","pull_request_comment"],"ai_reaction":"eyes","emoji":"✅","status_comment":true}],"archie":[{"workflow":"archie","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🏛️","status_comment":true}],"cloclo":[{"workflow":"cloclo","events":["discussion","discussion_comment","issue_comment","issues","pull_request","pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"📊","status_comment":true}],"craft":[{"workflow":"craft","events":["issues"],"ai_reaction":"eyes","emoji":"✍️","status_comment":true}],"dependabot-burner":[{"workflow":"dependabot-burner","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔥","status_comment":true}],"grumpy":[{"workflow":"grumpy-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true}],"matt":[{"workflow":"mattpocock-skills-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true}],"mergefest":[{"workflow":"mergefest","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"🔀","status_comment":true}],"nit":[{"workflow":"pr-nitpick-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true}],"plan":[{"workflow":"plan","events":["discussion_comment","issue_comment"],"ai_reaction":"eyes","emoji":"📋","status_comment":true}],"poem-bot":[{"workflow":"poem-bot","events":["issues"],"ai_reaction":"eyes","emoji":"🎭","status_comment":true}],"ponytail":[{"workflow":"ponytail-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"✂️","status_comment":true}],"review":[{"workflow":"design-decision-gate","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🏗️","status_comment":true},{"workflow":"pr-code-quality-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true},{"workflow":"test-quality-sentinel","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"ruflo":[{"workflow":"ruflo-backed-task","events":["issue_comment"],"ai_reaction":"eyes","status_comment":true}],"scout":[{"workflow":"scout","events":["discussion","discussion_comment","issue_comment","issues","pull_request","pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔭","status_comment":true}],"security-review":[{"workflow":"security-review","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔒","status_comment":true}],"smoke-agent-all-merged":[{"workflow":"smoke-agent-all-merged","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-all-none":[{"workflow":"smoke-agent-all-none","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-public-approved":[{"workflow":"smoke-agent-public-approved","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-public-none":[{"workflow":"smoke-agent-public-none","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-scoped-approved":[{"workflow":"smoke-agent-scoped-approved","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-aider":[{"workflow":"smoke-aider","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧑‍✈️","status_comment":true}],"smoke-call-workflow":[{"workflow":"smoke-call-workflow","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-checkout-pr-dispatch":[{"workflow":"smoke-checkout-pr-dispatch","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-claude":[{"workflow":"smoke-claude","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"heart","emoji":"🧪","status_comment":true}],"smoke-claude-on-copilot":[{"workflow":"smoke-claude-on-copilot","events":["pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-codex":[{"workflow":"smoke-codex","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"hooray","emoji":"🧪","status_comment":true}],"smoke-copilot":[{"workflow":"smoke-copilot","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-aoai-apikey":[{"workflow":"smoke-copilot-aoai-apikey","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-aoai-entra":[{"workflow":"smoke-copilot-aoai-entra","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-arm":[{"workflow":"smoke-copilot-arm","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-mai":[{"workflow":"smoke-copilot-mai","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"⚡","status_comment":true}],"smoke-copilot-sdk":[{"workflow":"smoke-copilot-sdk","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🔬","status_comment":true}],"smoke-copilot-small":[{"workflow":"smoke-copilot-small","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🪶","status_comment":true}],"smoke-create-cross-repo-pr":[{"workflow":"smoke-create-cross-repo-pr","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-crush":[{"workflow":"smoke-crush","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-cursor":[{"workflow":"smoke-cursor","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🖱️","status_comment":true}],"smoke-deepseek-harness":[{"workflow":"smoke-deepseek-harness","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-drive":[{"workflow":"smoke-drive","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"💾","status_comment":true}],"smoke-gemini":[{"workflow":"smoke-gemini","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧪","status_comment":true}],"smoke-github-claude":[{"workflow":"smoke-github-claude","events":["pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-goose":[{"workflow":"smoke-goose","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🪿","status_comment":true}],"smoke-kiro":[{"workflow":"smoke-kiro","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧭","status_comment":true}],"smoke-multi-pr":[{"workflow":"smoke-multi-pr","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-opencode":[{"workflow":"smoke-opencode","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧪","status_comment":true}],"smoke-otel-backends":[{"workflow":"smoke-otel-backends","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-pi":[{"workflow":"smoke-pi","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧪","status_comment":true}],"smoke-project":[{"workflow":"smoke-project","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-pydantic":[{"workflow":"smoke-pydantic","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🐍","status_comment":true}],"smoke-service-ports":[{"workflow":"smoke-service-ports","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-temporary-id":[{"workflow":"smoke-temporary-id","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-test-tools":[{"workflow":"smoke-test-tools","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-update-cross-repo-pr":[{"workflow":"smoke-update-cross-repo-pr","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"souschef":[{"workflow":"pr-sous-chef","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"👨‍🍳","status_comment":true}],"squad-plan":[{"workflow":"squad-plan","events":["issue_comment"],"ai_reaction":"eyes","emoji":"🧑‍🤝‍🧑","status_comment":true}],"summarize":[{"workflow":"pdf-summary","events":["issue_comment","issues"],"ai_reaction":"eyes","emoji":"📄","status_comment":true}],"tidy":[{"workflow":"tidy","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"🧹","status_comment":true}],"unbloat":[{"workflow":"unbloat-docs","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"📝","status_comment":true}]}' + GH_AW_SLASH_ROUTING: '{"*":[{"workflow":"skillet","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🍳","status_comment":true}],"ace":[{"workflow":"ace-editor","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"✏️","status_comment":true}],"approach-validator":[{"workflow":"approach-validator","events":["issue_comment","pull_request_comment"],"ai_reaction":"eyes","emoji":"✅","status_comment":true}],"archie":[{"workflow":"archie","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🏛️","status_comment":true}],"cloclo":[{"workflow":"cloclo","events":["discussion","discussion_comment","issue_comment","issues","pull_request","pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"📊","status_comment":true}],"craft":[{"workflow":"craft","events":["issues"],"ai_reaction":"eyes","emoji":"✍️","status_comment":true}],"dependabot-burner":[{"workflow":"dependabot-burner","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔥","status_comment":true}],"grumpy":[{"workflow":"grumpy-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true}],"matt":[{"workflow":"mattpocock-skills-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true}],"mergefest":[{"workflow":"mergefest","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"🔀","status_comment":true}],"nit":[{"workflow":"pr-nitpick-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true}],"plan":[{"workflow":"plan","events":["discussion_comment","issue_comment"],"ai_reaction":"eyes","emoji":"📋","status_comment":true}],"poem-bot":[{"workflow":"poem-bot","events":["issues"],"ai_reaction":"eyes","emoji":"🎭","status_comment":true}],"ponytail":[{"workflow":"ponytail-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"✂️","status_comment":true}],"review":[{"workflow":"design-decision-gate","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🏗️","status_comment":true},{"workflow":"pr-code-quality-reviewer","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔍","status_comment":true},{"workflow":"test-quality-sentinel","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"ruflo":[{"workflow":"ruflo-backed-task","events":["issue_comment"],"ai_reaction":"eyes","status_comment":true}],"scout":[{"workflow":"scout","events":["discussion","discussion_comment","issue_comment","issues","pull_request","pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔭","status_comment":true}],"security-review":[{"workflow":"security-review","events":["pull_request_comment","pull_request_review_comment"],"ai_reaction":"eyes","emoji":"🔒","status_comment":true}],"smoke-agent-all-merged":[{"workflow":"smoke-agent-all-merged","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-all-none":[{"workflow":"smoke-agent-all-none","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-public-approved":[{"workflow":"smoke-agent-public-approved","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-public-none":[{"workflow":"smoke-agent-public-none","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-agent-scoped-approved":[{"workflow":"smoke-agent-scoped-approved","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-aider":[{"workflow":"smoke-aider","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧑‍✈️","status_comment":true}],"smoke-call-workflow":[{"workflow":"smoke-call-workflow","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-checkout-pr-dispatch":[{"workflow":"smoke-checkout-pr-dispatch","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-claude":[{"workflow":"smoke-claude","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"heart","emoji":"🧪","status_comment":true}],"smoke-claude-on-copilot":[{"workflow":"smoke-claude-on-copilot","events":["pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-codex":[{"workflow":"smoke-codex","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"hooray","emoji":"🧪","status_comment":true}],"smoke-copilot":[{"workflow":"smoke-copilot","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-aoai-apikey":[{"workflow":"smoke-copilot-aoai-apikey","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-aoai-entra":[{"workflow":"smoke-copilot-aoai-entra","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-arm":[{"workflow":"smoke-copilot-arm","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-copilot-mai":[{"workflow":"smoke-copilot-mai","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"⚡","status_comment":true}],"smoke-copilot-sdk":[{"workflow":"smoke-copilot-sdk","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🔬","status_comment":true}],"smoke-copilot-small":[{"workflow":"smoke-copilot-small","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🪶","status_comment":true}],"smoke-create-cross-repo-pr":[{"workflow":"smoke-create-cross-repo-pr","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-crush":[{"workflow":"smoke-crush","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-cursor":[{"workflow":"smoke-cursor","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🖱️","status_comment":true}],"smoke-deepseek-harness":[{"workflow":"smoke-deepseek-harness","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-gemini":[{"workflow":"smoke-gemini","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧪","status_comment":true}],"smoke-github-claude":[{"workflow":"smoke-github-claude","events":["pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-goose":[{"workflow":"smoke-goose","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🪿","status_comment":true}],"smoke-kiro":[{"workflow":"smoke-kiro","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧭","status_comment":true}],"smoke-multi-pr":[{"workflow":"smoke-multi-pr","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-opencode":[{"workflow":"smoke-opencode","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧪","status_comment":true}],"smoke-otel-backends":[{"workflow":"smoke-otel-backends","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-pi":[{"workflow":"smoke-pi","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🧪","status_comment":true}],"smoke-project":[{"workflow":"smoke-project","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-pydantic":[{"workflow":"smoke-pydantic","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"rocket","emoji":"🐍","status_comment":true}],"smoke-service-ports":[{"workflow":"smoke-service-ports","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-temporary-id":[{"workflow":"smoke-temporary-id","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-test-tools":[{"workflow":"smoke-test-tools","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-update-cross-repo-pr":[{"workflow":"smoke-update-cross-repo-pr","events":["issue_comment","issues","pull_request","pull_request_comment"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"souschef":[{"workflow":"pr-sous-chef","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"👨‍🍳","status_comment":true}],"squad-plan":[{"workflow":"squad-plan","events":["issue_comment"],"ai_reaction":"eyes","emoji":"🧑‍🤝‍🧑","status_comment":true}],"summarize":[{"workflow":"pdf-summary","events":["issue_comment","issues"],"ai_reaction":"eyes","emoji":"📄","status_comment":true}],"tidy":[{"workflow":"tidy","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"🧹","status_comment":true}],"unbloat":[{"workflow":"unbloat-docs","events":["pull_request_comment"],"ai_reaction":"eyes","emoji":"📝","status_comment":true}]}' GH_AW_LABEL_ROUTING: '{"approach-proposal":[{"workflow":"approach-validator","events":["issues","pull_request"],"ai_reaction":"eyes","emoji":"✅","status_comment":true}],"ci-doctor":[{"workflow":"ci-doctor","events":["pull_request"],"ai_reaction":"eyes","emoji":"🏥","status_comment":true}],"cloclo":[{"workflow":"cloclo","events":["discussion","issues","pull_request"],"ai_reaction":"eyes","emoji":"📊","status_comment":true}],"dev":[{"workflow":"dev","events":["discussion","issues","pull_request"],"ai_reaction":"eyes","emoji":"💻","status_comment":true}],"necromancer":[{"workflow":"necromancer","events":["pull_request"],"ai_reaction":"eyes","emoji":"💀","status_comment":true}],"needs-design":[{"workflow":"approach-validator","events":["issues","pull_request"],"ai_reaction":"eyes","emoji":"✅","status_comment":true}],"smoke":[{"workflow":"smoke-copilot","events":["pull_request"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true},{"workflow":"smoke-copilot-aoai-apikey","events":["pull_request"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true},{"workflow":"smoke-copilot-aoai-entra","events":["pull_request"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true},{"workflow":"smoke-copilot-mai","events":["pull_request"],"ai_reaction":"eyes","emoji":"⚡","status_comment":true},{"workflow":"smoke-copilot-small","events":["pull_request"],"ai_reaction":"eyes","emoji":"🪶","status_comment":true},{"workflow":"smoke-otel-backends","events":["pull_request"],"ai_reaction":"eyes","emoji":"🧪","status_comment":true}],"smoke-sdk":[{"workflow":"smoke-copilot-sdk","events":["pull_request"],"ai_reaction":"eyes","emoji":"🔬","status_comment":true}]}' - GH_AW_HELP_COMMANDS: '[{"command":"*","description":"Reviews pull requests by mapping any slash command to a matching repository skill under .github/skills","centralized":true,"decentralized":false,"source_file":"skillet"},{"command":"ace","description":"Generates an ACE editor session link when invoked with /ace command on pull request comments","centralized":true,"decentralized":false,"source_file":"ace-editor"},{"command":"approach-validator","description":"Validates proposed technical approaches before implementation begins using a sequential multi-agent panel of Devil''s Advocate, Alternatives Scout, Implementation Estimator, and Dead End Detector","centralized":true,"decentralized":false,"source_file":"approach-validator"},{"command":"archie","description":"Generates Mermaid diagrams to visualize issue and pull request relationships when invoked with the /archie command","centralized":true,"decentralized":false,"source_file":"archie"},{"command":"cloclo","centralized":true,"decentralized":false,"source_file":"cloclo"},{"command":"craft","description":"Generates new agentic workflow markdown files based on user requests when invoked with /craft command","centralized":true,"decentralized":false,"source_file":"craft"},{"command":"dependabot-burner","description":"Runs one grouped Dependabot remediation wave from schedule, manual dispatch, or /dependabot-burner on pull requests","centralized":true,"decentralized":false,"source_file":"dependabot-burner"},{"command":"grumpy","description":"⚠️ DEPRECATED: Use PR Code Quality Reviewer (pr-code-quality-reviewer) instead. Performs critical code review with a focus on edge cases, potential bugs, and code quality issues","centralized":true,"decentralized":false,"source_file":"grumpy-reviewer"},{"command":"matt","description":"Reviews pull requests using Matt Pocock''s engineering skills to provide targeted, high-quality improvement suggestions based on the type of changes","centralized":true,"decentralized":false,"source_file":"mattpocock-skills-reviewer"},{"command":"mergefest","description":"Automatically merges the main branch into pull request branches when invoked with /mergefest command","centralized":true,"decentralized":false,"source_file":"mergefest"},{"command":"nit","description":"⚠️ DEPRECATED: Use PR Code Quality Reviewer (pr-code-quality-reviewer) instead. Provides detailed nitpicky code review focusing on style, best practices, and minor improvements","centralized":true,"decentralized":false,"source_file":"pr-nitpick-reviewer"},{"command":"plan","description":"Generates project plans and task breakdowns when invoked with /plan command in issues or PRs","centralized":true,"decentralized":false,"source_file":"plan"},{"command":"poem-bot","description":"Generates creative poems on specified themes when invoked with /poem-bot command","centralized":true,"decentralized":false,"source_file":"poem-bot"},{"command":"ponytail","description":"Reviews pull requests for unnecessary complexity using Ponytail","centralized":true,"decentralized":false,"source_file":"ponytail-reviewer"},{"command":"q","description":"Intelligent assistant that answers questions, analyzes repositories, and can create PRs for workflow optimizations","centralized":false,"decentralized":true,"source_file":"q"},{"command":"review","description":"Enforces Architecture Decision Records (ADRs) before implementation work can merge, detecting missing design decisions and generating draft ADRs using AI analysis","centralized":true,"decentralized":false,"source_file":"design-decision-gate"},{"command":"ruflo","description":"Runs a repository task inside GitHub Agentic Workflows while delegating inner planning and coordination to Ruflo","centralized":true,"decentralized":false,"source_file":"ruflo-backed-task"},{"command":"scout","description":"Performs deep research investigations using web search to gather and synthesize comprehensive information on any topic","centralized":true,"decentralized":false,"source_file":"scout"},{"command":"security-review","description":"Security-focused AI agent that reviews pull requests to identify changes that could weaken security posture or extend AWF boundaries","centralized":true,"decentralized":false,"source_file":"security-review"},{"command":"smoke-agent-all-merged","description":"Guard policy smoke test: repos=all, min-integrity=merged (most restrictive)","centralized":true,"decentralized":false,"source_file":"smoke-agent-all-merged"},{"command":"smoke-agent-all-none","description":"Guard policy smoke test: repos=all, min-integrity=none (most permissive)","centralized":true,"decentralized":false,"source_file":"smoke-agent-all-none"},{"command":"smoke-agent-public-approved","description":"Smoke test that validates assign-to-agent with the agentic-workflows custom agent","centralized":true,"decentralized":false,"source_file":"smoke-agent-public-approved"},{"command":"smoke-agent-public-none","description":"Guard policy smoke test: repos=public, min-integrity=none","centralized":true,"decentralized":false,"source_file":"smoke-agent-public-none"},{"command":"smoke-agent-scoped-approved","description":"Guard policy smoke test: repos=[github/gh-aw, github/*], min-integrity=approved (scoped patterns)","centralized":true,"decentralized":false,"source_file":"smoke-agent-scoped-approved"},{"command":"smoke-aider","description":"Smoke test workflow that validates Aider engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-aider"},{"command":"smoke-call-workflow","description":"Smoke test for the call-workflow safe output - orchestrator that calls a worker via workflow_call at compile-time fan-out","centralized":true,"decentralized":false,"source_file":"smoke-call-workflow"},{"command":"smoke-checkout-pr-dispatch","description":"Integration test validating that workflow_dispatch events with aw_context.item_type == ''pull_request'' correctly check out the PR branch","centralized":true,"decentralized":false,"source_file":"smoke-checkout-pr-dispatch"},{"command":"smoke-claude","description":"Smoke test workflow that validates Claude engine functionality by reviewing recent PRs twice daily","centralized":true,"decentralized":false,"source_file":"smoke-claude"},{"command":"smoke-claude-on-copilot","description":"Smoke test for Claude engine on GitHub Inference that posts a concise PR summary comment","centralized":true,"decentralized":false,"source_file":"smoke-claude-on-copilot"},{"command":"smoke-codex","description":"Smoke test workflow that validates Codex engine functionality by reviewing recent PRs twice daily","centralized":true,"decentralized":false,"source_file":"smoke-codex"},{"command":"smoke-copilot","description":"Smoke Copilot","centralized":true,"decentralized":false,"source_file":"smoke-copilot"},{"command":"smoke-copilot-aoai-apikey","description":"Smoke Copilot - AOAI (apikey)","centralized":true,"decentralized":false,"source_file":"smoke-copilot-aoai-apikey"},{"command":"smoke-copilot-aoai-entra","description":"Smoke Copilot - AOAI (Entra)","centralized":true,"decentralized":false,"source_file":"smoke-copilot-aoai-entra"},{"command":"smoke-copilot-arm","description":"Smoke Copilot ARM64","centralized":true,"decentralized":false,"source_file":"smoke-copilot-arm"},{"command":"smoke-copilot-mai","description":"Smoke test for MAI-Code-1-Flash (mai-code-1-flash-picker) — pricing: $0.75/M input, $0.075/M cached, $4.50/M output","centralized":true,"decentralized":false,"source_file":"smoke-copilot-mai"},{"command":"smoke-copilot-sdk","description":"Smoke Copilot SDK","centralized":true,"decentralized":false,"source_file":"smoke-copilot-sdk"},{"command":"smoke-copilot-small","description":"Smoke Copilot Small","centralized":true,"decentralized":false,"source_file":"smoke-copilot-small"},{"command":"smoke-create-cross-repo-pr","description":"Smoke test validating cross-repo pull request creation in github/gh-aw-side-repo","centralized":true,"decentralized":false,"source_file":"smoke-create-cross-repo-pr"},{"command":"smoke-crush","description":"Smoke test workflow that validates Crush engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-crush"},{"command":"smoke-cursor","description":"Smoke test workflow that validates Cursor engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-cursor"},{"command":"smoke-deepseek-harness","description":"Smoke test workflow that validates DeepSeek Harness engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-deepseek-harness"},{"command":"smoke-drive","description":"Smoke test workflow that validates experimental GitHub Drives memory","centralized":true,"decentralized":false,"source_file":"smoke-drive"},{"command":"smoke-gemini","description":"Smoke test workflow that validates Gemini engine functionality twice daily","centralized":true,"decentralized":false,"source_file":"smoke-gemini"},{"command":"smoke-github-claude","description":"Smoke test for Claude engine using GitHub provider that posts a concise PR summary comment","centralized":true,"decentralized":false,"source_file":"smoke-github-claude"},{"command":"smoke-goose","description":"Smoke test workflow that validates Goose engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-goose"},{"command":"smoke-kiro","description":"Smoke test workflow that validates Kiro engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-kiro"},{"command":"smoke-multi-pr","description":"Test creating multiple pull requests in a single workflow run","centralized":true,"decentralized":false,"source_file":"smoke-multi-pr"},{"command":"smoke-opencode","description":"Smoke test workflow that validates OpenCode engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-opencode"},{"command":"smoke-otel-backends","description":"Smoke test that validates OTEL span export and query access for Sentry, Grafana, and Datadog","centralized":true,"decentralized":false,"source_file":"smoke-otel-backends"},{"command":"smoke-pi","description":"Smoke test workflow that validates Pi engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-pi"},{"command":"smoke-project","description":"Smoke Project - Test project operations","centralized":true,"decentralized":false,"source_file":"smoke-project"},{"command":"smoke-pydantic","description":"Smoke test workflow that validates Pydantic AI engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-pydantic"},{"command":"smoke-service-ports","description":"Smoke test to validate --allow-host-service-ports with Redis service container","centralized":true,"decentralized":false,"source_file":"smoke-service-ports"},{"command":"smoke-temporary-id","description":"Test temporary ID functionality for issue chaining and cross-references","centralized":true,"decentralized":false,"source_file":"smoke-temporary-id"},{"command":"smoke-test-tools","description":"Smoke test to validate common development tools are available in the agent container","centralized":true,"decentralized":false,"source_file":"smoke-test-tools"},{"command":"smoke-update-cross-repo-pr","description":"Smoke test validating cross-repo pull request updates in github/gh-aw-side-repo by adding lines from Homer''s Odyssey to the README","centralized":true,"decentralized":false,"source_file":"smoke-update-cross-repo-pr"},{"command":"souschef","description":"Keeps open non-draft PRs moving toward maintainer investigation by posting targeted Copilot nudges","centralized":true,"decentralized":false,"source_file":"pr-sous-chef"},{"command":"squad","description":"Cast, connect, or adopt a Squad AI team for your repository","centralized":false,"decentralized":true,"source_file":"squad"},{"command":"squad-plan","description":"Uses Squad to plan an issue from the /squad-plan slash command and create Copilot-ready sub-issues","centralized":true,"decentralized":false,"source_file":"squad-plan"},{"command":"summarize","description":"pdf summarizer","centralized":true,"decentralized":false,"source_file":"pdf-summary"},{"command":"tidy","description":"Automatically formats and tidies code files (Go, JS, TypeScript) on schedule or command","centralized":true,"decentralized":false,"source_file":"tidy"},{"command":"unbloat","description":"Reviews and simplifies documentation by reducing verbosity while maintaining clarity and completeness","centralized":true,"decentralized":false,"source_file":"unbloat-docs"},{"command":"approach-proposal","description":"Validates proposed technical approaches before implementation begins using a sequential multi-agent panel of Devil''s Advocate, Alternatives Scout, Implementation Estimator, and Dead End Detector","centralized":false,"decentralized":false,"label":true,"source_file":"approach-validator"},{"command":"ci-doctor","description":"Investigates failed CI workflows to identify root causes and patterns, creating issues with diagnostic information; also reviews PR check failures when the ci-doctor label is applied","centralized":false,"decentralized":false,"label":true,"source_file":"ci-doctor"},{"command":"cloclo","centralized":false,"decentralized":false,"label":true,"source_file":"cloclo"},{"command":"dev","description":"Daily status report for gh-aw project","centralized":false,"decentralized":false,"label":true,"source_file":"dev"},{"command":"necromancer","description":"Investigates merge-ready pull requests, traces root-cause issues, and adds regression tests before merge","centralized":false,"decentralized":false,"label":true,"source_file":"necromancer"},{"command":"needs-design","description":"Validates proposed technical approaches before implementation begins using a sequential multi-agent panel of Devil''s Advocate, Alternatives Scout, Implementation Estimator, and Dead End Detector","centralized":false,"decentralized":false,"label":true,"source_file":"approach-validator"},{"command":"smoke","description":"Smoke Copilot - AOAI (apikey)","centralized":false,"decentralized":false,"label":true,"source_file":"smoke-copilot-aoai-apikey"},{"command":"smoke-sdk","description":"Smoke Copilot SDK","centralized":false,"decentralized":false,"label":true,"source_file":"smoke-copilot-sdk"}]' + GH_AW_HELP_COMMANDS: '[{"command":"*","description":"Reviews pull requests by mapping any slash command to a matching repository skill under .github/skills","centralized":true,"decentralized":false,"source_file":"skillet"},{"command":"ace","description":"Generates an ACE editor session link when invoked with /ace command on pull request comments","centralized":true,"decentralized":false,"source_file":"ace-editor"},{"command":"approach-validator","description":"Validates proposed technical approaches before implementation begins using a sequential multi-agent panel of Devil''s Advocate, Alternatives Scout, Implementation Estimator, and Dead End Detector","centralized":true,"decentralized":false,"source_file":"approach-validator"},{"command":"archie","description":"Generates Mermaid diagrams to visualize issue and pull request relationships when invoked with the /archie command","centralized":true,"decentralized":false,"source_file":"archie"},{"command":"cloclo","centralized":true,"decentralized":false,"source_file":"cloclo"},{"command":"craft","description":"Generates new agentic workflow markdown files based on user requests when invoked with /craft command","centralized":true,"decentralized":false,"source_file":"craft"},{"command":"dependabot-burner","description":"Runs one grouped Dependabot remediation wave from schedule, manual dispatch, or /dependabot-burner on pull requests","centralized":true,"decentralized":false,"source_file":"dependabot-burner"},{"command":"grumpy","description":"⚠️ DEPRECATED: Use PR Code Quality Reviewer (pr-code-quality-reviewer) instead. Performs critical code review with a focus on edge cases, potential bugs, and code quality issues","centralized":true,"decentralized":false,"source_file":"grumpy-reviewer"},{"command":"matt","description":"Reviews pull requests using Matt Pocock''s engineering skills to provide targeted, high-quality improvement suggestions based on the type of changes","centralized":true,"decentralized":false,"source_file":"mattpocock-skills-reviewer"},{"command":"mergefest","description":"Automatically merges the main branch into pull request branches when invoked with /mergefest command","centralized":true,"decentralized":false,"source_file":"mergefest"},{"command":"nit","description":"⚠️ DEPRECATED: Use PR Code Quality Reviewer (pr-code-quality-reviewer) instead. Provides detailed nitpicky code review focusing on style, best practices, and minor improvements","centralized":true,"decentralized":false,"source_file":"pr-nitpick-reviewer"},{"command":"plan","description":"Generates project plans and task breakdowns when invoked with /plan command in issues or PRs","centralized":true,"decentralized":false,"source_file":"plan"},{"command":"poem-bot","description":"Generates creative poems on specified themes when invoked with /poem-bot command","centralized":true,"decentralized":false,"source_file":"poem-bot"},{"command":"ponytail","description":"Reviews pull requests for unnecessary complexity using Ponytail","centralized":true,"decentralized":false,"source_file":"ponytail-reviewer"},{"command":"q","description":"Intelligent assistant that answers questions, analyzes repositories, and can create PRs for workflow optimizations","centralized":false,"decentralized":true,"source_file":"q"},{"command":"review","description":"Enforces Architecture Decision Records (ADRs) before implementation work can merge, detecting missing design decisions and generating draft ADRs using AI analysis","centralized":true,"decentralized":false,"source_file":"design-decision-gate"},{"command":"ruflo","description":"Runs a repository task inside GitHub Agentic Workflows while delegating inner planning and coordination to Ruflo","centralized":true,"decentralized":false,"source_file":"ruflo-backed-task"},{"command":"scout","description":"Performs deep research investigations using web search to gather and synthesize comprehensive information on any topic","centralized":true,"decentralized":false,"source_file":"scout"},{"command":"security-review","description":"Security-focused AI agent that reviews pull requests to identify changes that could weaken security posture or extend AWF boundaries","centralized":true,"decentralized":false,"source_file":"security-review"},{"command":"smoke-agent-all-merged","description":"Guard policy smoke test: repos=all, min-integrity=merged (most restrictive)","centralized":true,"decentralized":false,"source_file":"smoke-agent-all-merged"},{"command":"smoke-agent-all-none","description":"Guard policy smoke test: repos=all, min-integrity=none (most permissive)","centralized":true,"decentralized":false,"source_file":"smoke-agent-all-none"},{"command":"smoke-agent-public-approved","description":"Smoke test that validates assign-to-agent with the agentic-workflows custom agent","centralized":true,"decentralized":false,"source_file":"smoke-agent-public-approved"},{"command":"smoke-agent-public-none","description":"Guard policy smoke test: repos=public, min-integrity=none","centralized":true,"decentralized":false,"source_file":"smoke-agent-public-none"},{"command":"smoke-agent-scoped-approved","description":"Guard policy smoke test: repos=[github/gh-aw, github/*], min-integrity=approved (scoped patterns)","centralized":true,"decentralized":false,"source_file":"smoke-agent-scoped-approved"},{"command":"smoke-aider","description":"Smoke test workflow that validates Aider engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-aider"},{"command":"smoke-call-workflow","description":"Smoke test for the call-workflow safe output - orchestrator that calls a worker via workflow_call at compile-time fan-out","centralized":true,"decentralized":false,"source_file":"smoke-call-workflow"},{"command":"smoke-checkout-pr-dispatch","description":"Integration test validating that workflow_dispatch events with aw_context.item_type == ''pull_request'' correctly check out the PR branch","centralized":true,"decentralized":false,"source_file":"smoke-checkout-pr-dispatch"},{"command":"smoke-claude","description":"Smoke test workflow that validates Claude engine functionality by reviewing recent PRs twice daily","centralized":true,"decentralized":false,"source_file":"smoke-claude"},{"command":"smoke-claude-on-copilot","description":"Smoke test for Claude engine on GitHub Inference that posts a concise PR summary comment","centralized":true,"decentralized":false,"source_file":"smoke-claude-on-copilot"},{"command":"smoke-codex","description":"Smoke test workflow that validates Codex engine functionality by reviewing recent PRs twice daily","centralized":true,"decentralized":false,"source_file":"smoke-codex"},{"command":"smoke-copilot","description":"Smoke Copilot","centralized":true,"decentralized":false,"source_file":"smoke-copilot"},{"command":"smoke-copilot-aoai-apikey","description":"Smoke Copilot - AOAI (apikey)","centralized":true,"decentralized":false,"source_file":"smoke-copilot-aoai-apikey"},{"command":"smoke-copilot-aoai-entra","description":"Smoke Copilot - AOAI (Entra)","centralized":true,"decentralized":false,"source_file":"smoke-copilot-aoai-entra"},{"command":"smoke-copilot-arm","description":"Smoke Copilot ARM64","centralized":true,"decentralized":false,"source_file":"smoke-copilot-arm"},{"command":"smoke-copilot-mai","description":"Smoke test for MAI-Code-1-Flash (mai-code-1-flash-picker) — pricing: $0.75/M input, $0.075/M cached, $4.50/M output","centralized":true,"decentralized":false,"source_file":"smoke-copilot-mai"},{"command":"smoke-copilot-sdk","description":"Smoke Copilot SDK","centralized":true,"decentralized":false,"source_file":"smoke-copilot-sdk"},{"command":"smoke-copilot-small","description":"Smoke Copilot Small","centralized":true,"decentralized":false,"source_file":"smoke-copilot-small"},{"command":"smoke-create-cross-repo-pr","description":"Smoke test validating cross-repo pull request creation in github/gh-aw-side-repo","centralized":true,"decentralized":false,"source_file":"smoke-create-cross-repo-pr"},{"command":"smoke-crush","description":"Smoke test workflow that validates Crush engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-crush"},{"command":"smoke-cursor","description":"Smoke test workflow that validates Cursor engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-cursor"},{"command":"smoke-deepseek-harness","description":"Smoke test workflow that validates DeepSeek Harness engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-deepseek-harness"},{"command":"smoke-gemini","description":"Smoke test workflow that validates Gemini engine functionality twice daily","centralized":true,"decentralized":false,"source_file":"smoke-gemini"},{"command":"smoke-github-claude","description":"Smoke test for Claude engine using GitHub provider that posts a concise PR summary comment","centralized":true,"decentralized":false,"source_file":"smoke-github-claude"},{"command":"smoke-goose","description":"Smoke test workflow that validates Goose engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-goose"},{"command":"smoke-kiro","description":"Smoke test workflow that validates Kiro engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-kiro"},{"command":"smoke-multi-pr","description":"Test creating multiple pull requests in a single workflow run","centralized":true,"decentralized":false,"source_file":"smoke-multi-pr"},{"command":"smoke-opencode","description":"Smoke test workflow that validates OpenCode engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-opencode"},{"command":"smoke-otel-backends","description":"Smoke test that validates OTEL span export and query access for Sentry, Grafana, and Datadog","centralized":true,"decentralized":false,"source_file":"smoke-otel-backends"},{"command":"smoke-pi","description":"Smoke test workflow that validates Pi engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-pi"},{"command":"smoke-project","description":"Smoke Project - Test project operations","centralized":true,"decentralized":false,"source_file":"smoke-project"},{"command":"smoke-pydantic","description":"Smoke test workflow that validates Pydantic AI engine functionality","centralized":true,"decentralized":false,"source_file":"smoke-pydantic"},{"command":"smoke-service-ports","description":"Smoke test to validate --allow-host-service-ports with Redis service container","centralized":true,"decentralized":false,"source_file":"smoke-service-ports"},{"command":"smoke-temporary-id","description":"Test temporary ID functionality for issue chaining and cross-references","centralized":true,"decentralized":false,"source_file":"smoke-temporary-id"},{"command":"smoke-test-tools","description":"Smoke test to validate common development tools are available in the agent container","centralized":true,"decentralized":false,"source_file":"smoke-test-tools"},{"command":"smoke-update-cross-repo-pr","description":"Smoke test validating cross-repo pull request updates in github/gh-aw-side-repo by adding lines from Homer''s Odyssey to the README","centralized":true,"decentralized":false,"source_file":"smoke-update-cross-repo-pr"},{"command":"souschef","description":"Keeps open non-draft PRs moving toward maintainer investigation by posting targeted Copilot nudges","centralized":true,"decentralized":false,"source_file":"pr-sous-chef"},{"command":"squad","description":"Cast, connect, or adopt a Squad AI team for your repository","centralized":false,"decentralized":true,"source_file":"squad"},{"command":"squad-plan","description":"Uses Squad to plan an issue from the /squad-plan slash command and create Copilot-ready sub-issues","centralized":true,"decentralized":false,"source_file":"squad-plan"},{"command":"summarize","description":"pdf summarizer","centralized":true,"decentralized":false,"source_file":"pdf-summary"},{"command":"tidy","description":"Automatically formats and tidies code files (Go, JS, TypeScript) on schedule or command","centralized":true,"decentralized":false,"source_file":"tidy"},{"command":"unbloat","description":"Reviews and simplifies documentation by reducing verbosity while maintaining clarity and completeness","centralized":true,"decentralized":false,"source_file":"unbloat-docs"},{"command":"approach-proposal","description":"Validates proposed technical approaches before implementation begins using a sequential multi-agent panel of Devil''s Advocate, Alternatives Scout, Implementation Estimator, and Dead End Detector","centralized":false,"decentralized":false,"label":true,"source_file":"approach-validator"},{"command":"ci-doctor","description":"Investigates failed CI workflows to identify root causes and patterns, creating issues with diagnostic information; also reviews PR check failures when the ci-doctor label is applied","centralized":false,"decentralized":false,"label":true,"source_file":"ci-doctor"},{"command":"cloclo","centralized":false,"decentralized":false,"label":true,"source_file":"cloclo"},{"command":"dev","description":"Daily status report for gh-aw project","centralized":false,"decentralized":false,"label":true,"source_file":"dev"},{"command":"necromancer","description":"Investigates merge-ready pull requests, traces root-cause issues, and adds regression tests before merge","centralized":false,"decentralized":false,"label":true,"source_file":"necromancer"},{"command":"needs-design","description":"Validates proposed technical approaches before implementation begins using a sequential multi-agent panel of Devil''s Advocate, Alternatives Scout, Implementation Estimator, and Dead End Detector","centralized":false,"decentralized":false,"label":true,"source_file":"approach-validator"},{"command":"smoke","description":"Smoke Copilot - AOAI (apikey)","centralized":false,"decentralized":false,"label":true,"source_file":"smoke-copilot-aoai-apikey"},{"command":"smoke-sdk","description":"Smoke Copilot SDK","centralized":false,"decentralized":false,"label":true,"source_file":"smoke-copilot-sdk"}]' GH_AW_HELP_COMMAND_ENABLED: 'true' GH_AW_SLASH_COMMAND_DOCS_URL: 'https://github.github.com/gh-aw/reference/command-triggers/' with: diff --git a/pkg/workflow/schemas/github-workflow.json b/pkg/workflow/schemas/github-workflow.json index fd902c7129e..3a757bb4e95 100644 --- a/pkg/workflow/schemas/github-workflow.json +++ b/pkg/workflow/schemas/github-workflow.json @@ -260,9 +260,6 @@ "discussions": { "$ref": "#/definitions/permissions-level" }, - "drives": { - "$ref": "#/definitions/permissions-level" - }, "id-token": { "$ref": "#/definitions/permissions-level" }, From 0d6fcc938e60a9e88ba2ebdb14fee4f77b26635a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Aug 2026 13:59:19 +0000 Subject: [PATCH 5/5] fix: use reflect.TypeFor in MCP options embedding test Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com> --- pkg/workflow/mcp_renderer_types_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/workflow/mcp_renderer_types_test.go b/pkg/workflow/mcp_renderer_types_test.go index f17757488b4..e2c3c5525fc 100644 --- a/pkg/workflow/mcp_renderer_types_test.go +++ b/pkg/workflow/mcp_renderer_types_test.go @@ -12,8 +12,8 @@ func TestGitHubMCPOptionsEmbedCommonOptions(t *testing.T) { name string optionType reflect.Type }{ - {name: "docker", optionType: reflect.TypeOf(GitHubMCPDockerOptions{})}, - {name: "remote", optionType: reflect.TypeOf(GitHubMCPRemoteOptions{})}, + {name: "docker", optionType: reflect.TypeFor[GitHubMCPDockerOptions]()}, + {name: "remote", optionType: reflect.TypeFor[GitHubMCPRemoteOptions]()}, } for _, tt := range tests {