From 20f76d38127a30fcc8a7e4427bc74d31ac83b6f1 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 17 Feb 2026 16:57:42 +0000 Subject: [PATCH 1/5] remove top level github token --- .../docs/reference/frontmatter-full.md | 9 -- .../src/content/docs/reference/frontmatter.md | 24 +--- pkg/parser/schemas/main_workflow_schema.json | 4 - pkg/workflow/agentic_workflow_test.go | 36 ------ pkg/workflow/codex_engine.go | 4 +- pkg/workflow/compiler_orchestrator_test.go | 2 - .../compiler_orchestrator_workflow.go | 1 - .../compiler_safe_outputs_specialized.go | 2 +- pkg/workflow/compiler_safe_outputs_steps.go | 6 +- pkg/workflow/compiler_types.go | 1 - pkg/workflow/compiler_yaml_main_job.go | 2 +- pkg/workflow/copilot_engine_execution.go | 18 +-- pkg/workflow/copilot_engine_installation.go | 5 +- pkg/workflow/copilot_participant_steps.go | 12 +- pkg/workflow/create_issue.go | 13 +- pkg/workflow/create_project_token_test.go | 5 - pkg/workflow/create_pull_request.go | 1 - pkg/workflow/frontmatter_types.go | 4 - pkg/workflow/github_token.go | 52 ++------ pkg/workflow/github_token_test.go | 116 ++++++------------ pkg/workflow/http_mcp_env_vars_test.go | 4 +- pkg/workflow/imports.go | 3 - pkg/workflow/mcp_environment.go | 2 +- pkg/workflow/mcp_setup_generator.go | 4 +- pkg/workflow/plugin_compilation_test.go | 23 +--- pkg/workflow/plugin_installation_test.go | 2 +- pkg/workflow/pr.go | 4 +- pkg/workflow/safe_outputs_env.go | 36 ++++-- ...safe_outputs_handler_manager_token_test.go | 5 - pkg/workflow/safe_outputs_steps.go | 40 +++--- 30 files changed, 142 insertions(+), 298 deletions(-) diff --git a/docs/src/content/docs/reference/frontmatter-full.md b/docs/src/content/docs/reference/frontmatter-full.md index ea6cab61d6c..47f19f1ecb1 100644 --- a/docs/src/content/docs/reference/frontmatter-full.md +++ b/docs/src/content/docs/reference/frontmatter-full.md @@ -3777,15 +3777,6 @@ safe-inputs: # (optional) runtimes: {} - -# GitHub token expression to use for all steps that require GitHub authentication. -# Typically a secret reference like ${{ secrets.GITHUB_TOKEN }} or ${{ -# secrets.CUSTOM_PAT }}. If not specified, defaults to ${{ -# secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}. This value can be -# overridden by safe-outputs github-token or individual safe-output github-token -# fields. -# (optional) -github-token: "${{ secrets.GITHUB_TOKEN }}" --- ``` diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md index 30897156f94..5790327aa80 100644 --- a/docs/src/content/docs/reference/frontmatter.md +++ b/docs/src/content/docs/reference/frontmatter.md @@ -84,23 +84,6 @@ metadata: Metadata provides a flexible way to add descriptive information to workflows without affecting execution. -### GitHub Token (`github-token:`) - -Configures the default GitHub token for engine authentication, checkout steps, and safe-output operations. - -```yaml wrap -github-token: ${{ secrets.CUSTOM_PAT }} -``` - -**Token precedence** (highest to lowest): - -1. Individual safe-output `github-token` (e.g., `create-issue.github-token`) -2. Safe-outputs global `github-token` -3. Top-level `github-token` -4. Default: `${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}` - -See [Authentication](/gh-aw/reference/auth/) for complete documentation. - ### Plugins (`plugins:`) :::caution[Experimental Feature] @@ -127,10 +110,9 @@ plugins: **Token precedence** for plugin installation (highest to lowest): 1. Custom `plugins.github-token` from object format -2. Custom top-level `github-token` -3. `${{ secrets.GH_AW_PLUGINS_TOKEN }}` -4. `${{ secrets.GH_AW_GITHUB_TOKEN }}` -5. `${{ secrets.GITHUB_TOKEN }}` (default) +2. `${{ secrets.GH_AW_PLUGINS_TOKEN }}` +3. `${{ secrets.GH_AW_GITHUB_TOKEN }}` +4. `${{ secrets.GITHUB_TOKEN }}` (default) Each plugin repository must be specified in `org/repo` format. The compiler generates installation steps that run after the engine CLI is installed but before workflow execution begins. diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json index b5a7a65e026..77e4aa7176f 100644 --- a/pkg/parser/schemas/main_workflow_schema.json +++ b/pkg/parser/schemas/main_workflow_schema.json @@ -6666,10 +6666,6 @@ } }, "additionalProperties": false - }, - "github-token": { - "$ref": "#/$defs/github_token", - "description": "GitHub token expression to use for all steps that require GitHub authentication. Typically a secret reference like ${{ secrets.GITHUB_TOKEN }} or ${{ secrets.CUSTOM_PAT }}. If not specified, defaults to ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}. This value can be overridden by safe-outputs github-token or individual safe-output github-token fields." } }, "additionalProperties": false, diff --git a/pkg/workflow/agentic_workflow_test.go b/pkg/workflow/agentic_workflow_test.go index 1d14afda088..792e249b4b7 100644 --- a/pkg/workflow/agentic_workflow_test.go +++ b/pkg/workflow/agentic_workflow_test.go @@ -33,13 +33,6 @@ func workflowDataWithAgenticWorkflows(options ...func(*WorkflowData)) *WorkflowD return wd } -// withCustomToken is an option for workflowDataWithAgenticWorkflows -func withCustomToken(token string) func(*WorkflowData) { - return func(wd *WorkflowData) { - wd.GitHubToken = token - } -} - // withImportedFiles is an option for workflowDataWithAgenticWorkflows func withImportedFiles(files ...string) func(*WorkflowData) { return func(wd *WorkflowData) { @@ -173,35 +166,6 @@ func TestAgenticWorkflowsInstallStepIncludesGHToken(t *testing.T) { "install step should copy gh-aw binary to /opt/gh-aw for MCP server containerization") } -func TestAgenticWorkflowsInstallStepWithCustomToken(t *testing.T) { - // Create workflow data using helper with custom token option - workflowData := workflowDataWithAgenticWorkflows( - withCustomToken("${{ secrets.CUSTOM_PAT }}"), - ) - - // Create compiler using helper - c := testCompiler() - - // Generate MCP setup - var yaml strings.Builder - engine := NewCopilotEngine() - - c.generateMCPSetup(&yaml, workflowData.Tools, engine, workflowData) - result := yaml.String() - - // Verify the install step is present - assert.Contains(t, result, "Install gh-aw extension", - "MCP setup should include gh-aw installation step even with custom token") - - // Verify GH_TOKEN environment variable is set with the custom token - assert.Contains(t, result, "GH_TOKEN: ${{ secrets.CUSTOM_PAT }}", - "install step should use custom GitHub token when specified in workflow config") - - // Verify it doesn't use the default token when custom is provided - assert.NotContains(t, result, "GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", - "install step should not use default token fallback when custom token is specified") -} - func TestAgenticWorkflowsInstallStepSkippedWithImport(t *testing.T) { // Create workflow data using helper with imported files option workflowData := workflowDataWithAgenticWorkflows( diff --git a/pkg/workflow/codex_engine.go b/pkg/workflow/codex_engine.go index 475895a3c40..2742dced319 100644 --- a/pkg/workflow/codex_engine.go +++ b/pkg/workflow/codex_engine.go @@ -244,8 +244,8 @@ mkdir -p "$CODEX_HOME/logs" } } - // Get effective GitHub token based on precedence: top-level github-token > default - effectiveGitHubToken := getEffectiveGitHubToken("", workflowData.GitHubToken) + // Get effective GitHub token based on precedence: custom token > default + effectiveGitHubToken := getEffectiveGitHubToken("") env := map[string]string{ "CODEX_API_KEY": "${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }}", diff --git a/pkg/workflow/compiler_orchestrator_test.go b/pkg/workflow/compiler_orchestrator_test.go index 584c445c440..2a48301b320 100644 --- a/pkg/workflow/compiler_orchestrator_test.go +++ b/pkg/workflow/compiler_orchestrator_test.go @@ -670,7 +670,6 @@ engine: copilot name: Test Workflow description: Test description source: test-source -github-token: ${{ secrets.GITHUB_TOKEN }} --- # Test Workflow @@ -690,7 +689,6 @@ Test content assert.Equal(t, "Test Workflow", workflowData.FrontmatterName, "Name should be set") assert.Equal(t, "Test description", workflowData.Description, "Description should be set") assert.Equal(t, "test-source", workflowData.Source, "Source should be set") - assert.Equal(t, "${{ secrets.GITHUB_TOKEN }}", workflowData.GitHubToken, "GitHub token should be set") assert.Equal(t, "copilot", workflowData.AI, "AI engine should be set") assert.NotNil(t, workflowData.EngineConfig, "EngineConfig should be set") assert.NotNil(t, workflowData.ParsedTools, "ParsedTools should be initialized") diff --git a/pkg/workflow/compiler_orchestrator_workflow.go b/pkg/workflow/compiler_orchestrator_workflow.go index 8ccab3c5502..5b06d7c457d 100644 --- a/pkg/workflow/compiler_orchestrator_workflow.go +++ b/pkg/workflow/compiler_orchestrator_workflow.go @@ -152,7 +152,6 @@ func (c *Compiler) buildInitialWorkflowData( ToolsStartupTimeout: toolsResult.toolsStartupTimeout, TrialMode: c.trialMode, TrialLogicalRepo: c.trialLogicalRepoSlug, - GitHubToken: extractStringFromMap(result.Frontmatter, "github-token", nil), StrictMode: c.strictMode, SecretMasking: toolsResult.secretMasking, ParsedFrontmatter: toolsResult.parsedFrontmatter, diff --git a/pkg/workflow/compiler_safe_outputs_specialized.go b/pkg/workflow/compiler_safe_outputs_specialized.go index b78454a9ec1..4d34f87e2e1 100644 --- a/pkg/workflow/compiler_safe_outputs_specialized.go +++ b/pkg/workflow/compiler_safe_outputs_specialized.go @@ -127,7 +127,7 @@ func (c *Compiler) buildCreateProjectStepConfig(data *WorkflowData, mainJobName // Get the effective token using the Projects-specific precedence chain // This includes fallback to GH_AW_PROJECT_GITHUB_TOKEN if no custom token is configured // Note: Projects v2 requires a PAT or GitHub App - the default GITHUB_TOKEN cannot work - effectiveToken := getEffectiveProjectGitHubToken(cfg.GitHubToken, data.GitHubToken) + effectiveToken := getEffectiveProjectGitHubToken(cfg.GitHubToken) // Always expose the effective token as GH_AW_PROJECT_GITHUB_TOKEN environment variable // The JavaScript code checks process.env.GH_AW_PROJECT_GITHUB_TOKEN to provide helpful error messages diff --git a/pkg/workflow/compiler_safe_outputs_steps.go b/pkg/workflow/compiler_safe_outputs_steps.go index d97e565769b..40a79ecff1c 100644 --- a/pkg/workflow/compiler_safe_outputs_steps.go +++ b/pkg/workflow/compiler_safe_outputs_steps.go @@ -210,12 +210,12 @@ func (c *Compiler) buildHandlerManagerStep(data *WorkflowData) []string { // Check update-project first (highest priority) if data.SafeOutputs.UpdateProjects != nil && data.SafeOutputs.UpdateProjects.Project != "" { projectURL = data.SafeOutputs.UpdateProjects.Project - projectToken = getEffectiveProjectGitHubToken(data.SafeOutputs.UpdateProjects.GitHubToken, data.GitHubToken) + projectToken = getEffectiveProjectGitHubToken(data.SafeOutputs.UpdateProjects.GitHubToken) consolidatedSafeOutputsStepsLog.Printf("Setting GH_AW_PROJECT_URL from update-project config: %s", projectURL) consolidatedSafeOutputsStepsLog.Printf("Setting GH_AW_PROJECT_GITHUB_TOKEN from update-project config") } else if data.SafeOutputs.CreateProjectStatusUpdates != nil && data.SafeOutputs.CreateProjectStatusUpdates.Project != "" { projectURL = data.SafeOutputs.CreateProjectStatusUpdates.Project - projectToken = getEffectiveProjectGitHubToken(data.SafeOutputs.CreateProjectStatusUpdates.GitHubToken, data.GitHubToken) + projectToken = getEffectiveProjectGitHubToken(data.SafeOutputs.CreateProjectStatusUpdates.GitHubToken) consolidatedSafeOutputsStepsLog.Printf("Setting GH_AW_PROJECT_URL from create-project-status-update config: %s", projectURL) consolidatedSafeOutputsStepsLog.Printf("Setting GH_AW_PROJECT_GITHUB_TOKEN from create-project-status-update config") } @@ -223,7 +223,7 @@ func (c *Compiler) buildHandlerManagerStep(data *WorkflowData) []string { // Check create-project for token even if no URL is set (create-project doesn't have a project URL field) // This ensures GH_AW_PROJECT_GITHUB_TOKEN is set when create-project is configured if projectToken == "" && data.SafeOutputs.CreateProjects != nil { - projectToken = getEffectiveProjectGitHubToken(data.SafeOutputs.CreateProjects.GitHubToken, data.GitHubToken) + projectToken = getEffectiveProjectGitHubToken(data.SafeOutputs.CreateProjects.GitHubToken) consolidatedSafeOutputsStepsLog.Printf("Setting GH_AW_PROJECT_GITHUB_TOKEN from create-project config") } diff --git a/pkg/workflow/compiler_types.go b/pkg/workflow/compiler_types.go index c7fd19ee9fb..fc5bbe538e2 100644 --- a/pkg/workflow/compiler_types.go +++ b/pkg/workflow/compiler_types.go @@ -441,7 +441,6 @@ type WorkflowData struct { Runtimes map[string]any // runtime version overrides from frontmatter PluginInfo *PluginInfo // Consolidated plugin information (plugins, custom token, MCP configs) ToolsTimeout int // timeout in seconds for tool/MCP operations (0 = use engine default) - GitHubToken string // top-level github-token expression from frontmatter ToolsStartupTimeout int // timeout in seconds for MCP server startup (0 = use engine default) Features map[string]any // feature flags and configuration options from frontmatter (supports bool and string values) ActionCache *ActionCache // cache for action pin resolutions diff --git a/pkg/workflow/compiler_yaml_main_job.go b/pkg/workflow/compiler_yaml_main_job.go index 7fddec9c8a9..3c3aa823407 100644 --- a/pkg/workflow/compiler_yaml_main_job.go +++ b/pkg/workflow/compiler_yaml_main_job.go @@ -31,7 +31,7 @@ func (c *Compiler) generateMainJobSteps(yaml *strings.Builder, data *WorkflowDat // yaml.WriteString(fmt.Sprintf(" path: %s\n", trialTargetRepoName[1])) // } } - effectiveToken := getEffectiveGitHubToken("", data.GitHubToken) + effectiveToken := getEffectiveGitHubToken("") fmt.Fprintf(yaml, " token: %s\n", effectiveToken) } diff --git a/pkg/workflow/copilot_engine_execution.go b/pkg/workflow/copilot_engine_execution.go index a6edbebf5bc..ef63b4a1e4b 100644 --- a/pkg/workflow/copilot_engine_execution.go +++ b/pkg/workflow/copilot_engine_execution.go @@ -228,16 +228,10 @@ COPILOT_CLI_INSTRUCTION="$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" } // Use COPILOT_GITHUB_TOKEN - // If github-token is specified at workflow level, use that instead - var copilotGitHubToken string - if workflowData.GitHubToken != "" { - copilotGitHubToken = workflowData.GitHubToken - } else { - // #nosec G101 -- This is NOT a hardcoded credential. It's a GitHub Actions expression template - // that GitHub Actions runtime replaces with the actual secret value. The string "${{ secrets.COPILOT_GITHUB_TOKEN }}" - // is a placeholder, not an actual credential. - copilotGitHubToken = "${{ secrets.COPILOT_GITHUB_TOKEN }}" - } + // #nosec G101 -- This is NOT a hardcoded credential. It's a GitHub Actions expression template + // that GitHub Actions runtime replaces with the actual secret value. The string "${{ secrets.COPILOT_GITHUB_TOKEN }}" + // is a placeholder, not an actual credential. + copilotGitHubToken := "${{ secrets.COPILOT_GITHUB_TOKEN }}" env := map[string]string{ "XDG_CONFIG_HOME": "/home/runner", @@ -259,8 +253,8 @@ COPILOT_CLI_INSTRUCTION="$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" if hasGitHubTool(workflowData.ParsedTools) { customGitHubToken := getGitHubToken(workflowData.Tools["github"]) - // Use effective token with precedence: custom > top-level > default - effectiveToken := getEffectiveGitHubToken(customGitHubToken, workflowData.GitHubToken) + // Use effective token with precedence: custom > default + effectiveToken := getEffectiveGitHubToken(customGitHubToken) env["GITHUB_MCP_SERVER_TOKEN"] = effectiveToken } diff --git a/pkg/workflow/copilot_engine_installation.go b/pkg/workflow/copilot_engine_installation.go index 7139c51388e..2529b04a27f 100644 --- a/pkg/workflow/copilot_engine_installation.go +++ b/pkg/workflow/copilot_engine_installation.go @@ -113,11 +113,8 @@ func (e *CopilotEngine) GetInstallationSteps(workflowData *WorkflowData) []GitHu // Add plugin installation steps after Copilot CLI installation if workflowData.PluginInfo != nil && len(workflowData.PluginInfo.Plugins) > 0 { copilotInstallLog.Printf("Adding plugin installation steps: %d plugins", len(workflowData.PluginInfo.Plugins)) - // Use plugin-specific token if provided, otherwise use top-level github-token + // Use plugin-specific token if provided tokenToUse := workflowData.PluginInfo.CustomToken - if tokenToUse == "" { - tokenToUse = workflowData.GitHubToken - } pluginSteps := GeneratePluginInstallationSteps(workflowData.PluginInfo.Plugins, "copilot", tokenToUse) steps = append(steps, pluginSteps...) } diff --git a/pkg/workflow/copilot_participant_steps.go b/pkg/workflow/copilot_participant_steps.go index deb5e7fa20e..216321ce922 100644 --- a/pkg/workflow/copilot_participant_steps.go +++ b/pkg/workflow/copilot_participant_steps.go @@ -18,8 +18,6 @@ type CopilotParticipantConfig struct { CustomToken string // SafeOutputsToken is the GitHub token from the safe-outputs config SafeOutputsToken string - // WorkflowToken is the top-level GitHub token from the workflow - WorkflowToken string // ConditionStepID is the step ID to check for output (e.g., "create_issue", "create_pull_request") ConditionStepID string // ConditionOutputKey is the output key to check (e.g., "issue_number", "pull_request_url") @@ -54,14 +52,20 @@ func buildCopilotParticipantSteps(config CopilotParticipantConfig) []string { } } + // Choose the first non-empty custom token for precedence + effectiveCustomToken := config.CustomToken + if effectiveCustomToken == "" { + effectiveCustomToken = config.SafeOutputsToken + } + // Use agent token preference if adding copilot as participant, otherwise use regular token var effectiveToken string if hasCopilotParticipant { copilotParticipantLog.Print("Using agent token preference") - effectiveToken = getEffectiveAgentGitHubToken(config.CustomToken, getEffectiveAgentGitHubToken(config.SafeOutputsToken, config.WorkflowToken)) + effectiveToken = getEffectiveAgentGitHubToken(effectiveCustomToken) } else { copilotParticipantLog.Print("Using regular GitHub token") - effectiveToken = getEffectiveGitHubToken(config.CustomToken, getEffectiveGitHubToken(config.SafeOutputsToken, config.WorkflowToken)) + effectiveToken = getEffectiveGitHubToken(effectiveCustomToken) } // Generate participant-specific steps diff --git a/pkg/workflow/create_issue.go b/pkg/workflow/create_issue.go index 36b21f22121..b10467ed1b1 100644 --- a/pkg/workflow/create_issue.go +++ b/pkg/workflow/create_issue.go @@ -99,11 +99,17 @@ func filterNonCopilotAssignees(assignees []string) []string { // buildCopilotAssignmentStep generates a post-step for assigning copilot to created issues // This step uses the agent token with full precedence chain -func buildCopilotAssignmentStep(configToken, safeOutputsToken, workflowToken string) []string { +func buildCopilotAssignmentStep(configToken, safeOutputsToken string) []string { var steps []string + // Choose the first non-empty custom token for precedence + effectiveCustomToken := configToken + if effectiveCustomToken == "" { + effectiveCustomToken = safeOutputsToken + } + // Get the effective agent token with full precedence chain - effectiveToken := getEffectiveAgentGitHubToken(configToken, getEffectiveAgentGitHubToken(safeOutputsToken, workflowToken)) + effectiveToken := getEffectiveAgentGitHubToken(effectiveCustomToken) steps = append(steps, " - name: Assign Copilot to created issues\n") steps = append(steps, " if: steps.create_issue.outputs.issues_to_assign_copilot != ''\n") @@ -188,7 +194,6 @@ func (c *Compiler) buildCreateOutputIssueJob(data *WorkflowData, mainJobName str ParticipantType: "assignee", CustomToken: data.SafeOutputs.CreateIssues.GitHubToken, SafeOutputsToken: safeOutputsToken, - WorkflowToken: data.GitHubToken, ConditionStepID: "create_issue", ConditionOutputKey: "issue_number", }) @@ -196,7 +201,7 @@ func (c *Compiler) buildCreateOutputIssueJob(data *WorkflowData, mainJobName str // Add post-step for copilot assignment using agent token if assignCopilot { - postSteps = append(postSteps, buildCopilotAssignmentStep(data.SafeOutputs.CreateIssues.GitHubToken, safeOutputsToken, data.GitHubToken)...) + postSteps = append(postSteps, buildCopilotAssignmentStep(data.SafeOutputs.CreateIssues.GitHubToken, safeOutputsToken)...) } // Create outputs for the job diff --git a/pkg/workflow/create_project_token_test.go b/pkg/workflow/create_project_token_test.go index fd1042406a4..c632474949d 100644 --- a/pkg/workflow/create_project_token_test.go +++ b/pkg/workflow/create_project_token_test.go @@ -78,11 +78,6 @@ func TestCreateProjectGitHubTokenEnvVar(t *testing.T) { SafeOutputs: compiler.extractSafeOutputsConfig(tt.frontmatter), } - // Set top-level github-token if present in frontmatter - if githubToken, ok := tt.frontmatter["github-token"].(string); ok { - workflowData.GitHubToken = githubToken - } - // Build the create_project step config stepConfig := compiler.buildCreateProjectStepConfig(workflowData, "main", false) diff --git a/pkg/workflow/create_pull_request.go b/pkg/workflow/create_pull_request.go index aa27623e797..f01ec166790 100644 --- a/pkg/workflow/create_pull_request.go +++ b/pkg/workflow/create_pull_request.go @@ -150,7 +150,6 @@ func (c *Compiler) buildCreateOutputPullRequestJob(data *WorkflowData, mainJobNa ParticipantType: "reviewer", CustomToken: data.SafeOutputs.CreatePullRequests.GitHubToken, SafeOutputsToken: safeOutputsToken, - WorkflowToken: data.GitHubToken, ConditionStepID: "create_pull_request", ConditionOutputKey: "pull_request_url", }) diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go index 4b53e6caf03..d488b373994 100644 --- a/pkg/workflow/frontmatter_types.go +++ b/pkg/workflow/frontmatter_types.go @@ -149,7 +149,6 @@ type FrontmatterConfig struct { // Metadata Metadata map[string]string `json:"metadata,omitempty"` // Custom metadata key-value pairs SecretMasking *SecretMaskingConfig `json:"secret-masking,omitempty"` - GithubToken string `json:"github-token,omitempty"` // Command/bot configuration Roles []string `json:"roles,omitempty"` @@ -657,9 +656,6 @@ func (fc *FrontmatterConfig) ToMap() map[string]any { if fc.SecretMasking != nil { result["secret-masking"] = fc.SecretMasking } - if fc.GithubToken != "" { - result["github-token"] = fc.GithubToken - } if fc.Roles != nil { result["roles"] = fc.Roles } diff --git a/pkg/workflow/github_token.go b/pkg/workflow/github_token.go index 8aa5a7c57ad..75c2c194ac0 100644 --- a/pkg/workflow/github_token.go +++ b/pkg/workflow/github_token.go @@ -6,35 +6,25 @@ var tokenLog = logger.New("workflow:github_token") // getEffectiveGitHubToken returns the GitHub token to use, with precedence: // 1. Custom token passed as parameter (e.g., from tool-specific config) -// 2. Top-level github-token from frontmatter -// 3. Default fallback: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} -func getEffectiveGitHubToken(customToken, toplevelToken string) string { +// 2. Default fallback: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} +func getEffectiveGitHubToken(customToken string) string { if customToken != "" { tokenLog.Print("Using custom GitHub token") return customToken } - if toplevelToken != "" { - tokenLog.Print("Using top-level GitHub token from frontmatter") - return toplevelToken - } tokenLog.Print("Using default GitHub token fallback") return "${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" } // getEffectiveSafeOutputGitHubToken returns the GitHub token to use for safe output operations, with precedence: // 1. Custom token passed as parameter (e.g., from per-output config) -// 2. Top-level github-token from frontmatter -// 3. Default fallback: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} -// This simpler chain ensures safe outputs use: safe outputs token -> workflow token -> GH_AW_GITHUB_TOKEN -> GitHub Actions token -func getEffectiveSafeOutputGitHubToken(customToken, toplevelToken string) string { +// 2. Default fallback: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} +// This simpler chain ensures safe outputs use: safe outputs token -> GH_AW_GITHUB_TOKEN -> GitHub Actions token +func getEffectiveSafeOutputGitHubToken(customToken string) string { if customToken != "" { tokenLog.Print("Using custom safe output GitHub token") return customToken } - if toplevelToken != "" { - tokenLog.Print("Using top-level safe output GitHub token from frontmatter") - return toplevelToken - } tokenLog.Print("Using default safe output GitHub token (GH_AW_GITHUB_TOKEN || GITHUB_TOKEN)") return "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" } @@ -43,44 +33,33 @@ func getEffectiveSafeOutputGitHubToken(customToken, toplevelToken string) string // with precedence: // 1. Custom token passed as parameter (e.g., from safe-outputs config github-token field) // 2. secrets.COPILOT_GITHUB_TOKEN (recommended token for Copilot operations) -// 3. secrets.GH_AW_GITHUB_TOKEN (legacy fallback for backward compatibility) // Note: The default GITHUB_TOKEN is NOT included as a fallback because it does not have // permission to create agent sessions, assign issues to bots, or add bots as reviewers. // This is used for safe outputs that interact with GitHub Copilot features: // - create-agent-session // - assigning "copilot" to issues // - adding "copilot" as PR reviewer -func getEffectiveCopilotGitHubToken(customToken, toplevelToken string) string { +func getEffectiveCopilotGitHubToken(customToken string) string { if customToken != "" { tokenLog.Print("Using custom Copilot GitHub token") return customToken } - if toplevelToken != "" { - tokenLog.Print("Using top-level Copilot GitHub token from frontmatter") - return toplevelToken - } - tokenLog.Print("Using default Copilot GitHub token fallback") - return "${{ secrets.COPILOT_GITHUB_TOKEN || secrets.GH_AW_GITHUB_TOKEN }}" + return "${{ secrets.COPILOT_GITHUB_TOKEN }}" } // getEffectiveAgentGitHubToken returns the GitHub token to use for agent assignment operations, // with precedence: // 1. Custom token passed as parameter (e.g., from safe-outputs config github-token field) -// 2. Top-level github-token from frontmatter -// 3. secrets.GH_AW_AGENT_TOKEN (recommended token for agent assignment with elevated permissions) -// 4. secrets.GH_AW_GITHUB_TOKEN (fallback with potentially sufficient permissions) -// 5. secrets.GITHUB_TOKEN (last resort, may lack permissions for bot assignment) +// 2. secrets.GH_AW_AGENT_TOKEN (recommended token for agent assignment with elevated permissions) +// 3. secrets.GH_AW_GITHUB_TOKEN (fallback with potentially sufficient permissions) +// 4. secrets.GITHUB_TOKEN (last resort, may lack permissions for bot assignment) // Note: Assigning bots (like copilot-swe-agent) requires permissions that GITHUB_TOKEN may not have. // It's recommended to configure GH_AW_AGENT_TOKEN or GH_AW_GITHUB_TOKEN with appropriate permissions. -func getEffectiveAgentGitHubToken(customToken, toplevelToken string) string { +func getEffectiveAgentGitHubToken(customToken string) string { if customToken != "" { tokenLog.Print("Using custom agent GitHub token") return customToken } - if toplevelToken != "" { - tokenLog.Print("Using top-level agent GitHub token from frontmatter") - return toplevelToken - } tokenLog.Print("Using default agent GitHub token fallback chain (GH_AW_AGENT_TOKEN || GH_AW_GITHUB_TOKEN || GITHUB_TOKEN)") return "${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" } @@ -88,21 +67,16 @@ func getEffectiveAgentGitHubToken(customToken, toplevelToken string) string { // getEffectiveProjectGitHubToken returns the GitHub token to use for GitHub Projects v2 operations, // with precedence: // 1. Custom token passed as parameter (e.g., from safe-outputs.update-project.github-token) -// 2. Top-level github-token from frontmatter -// 3. secrets.GH_AW_PROJECT_GITHUB_TOKEN (required token for Projects v2 operations) +// 2. secrets.GH_AW_PROJECT_GITHUB_TOKEN (required token for Projects v2 operations) // Note: GitHub Projects v2 requires a PAT (classic with project + repo scopes, or fine-grained // with Projects: Read+Write) or GitHub App. The default GITHUB_TOKEN cannot access Projects v2. // You must configure GH_AW_PROJECT_GITHUB_TOKEN or provide a custom token for Projects v2 operations. // No fallback to GITHUB_TOKEN is provided as it will never work for Projects v2 operations. -func getEffectiveProjectGitHubToken(customToken, toplevelToken string) string { +func getEffectiveProjectGitHubToken(customToken string) string { if customToken != "" { tokenLog.Print("Using custom project GitHub token") return customToken } - if toplevelToken != "" { - tokenLog.Print("Using top-level GitHub token for project operations") - return toplevelToken - } tokenLog.Print("Using GH_AW_PROJECT_GITHUB_TOKEN for project operations") return "${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}" } diff --git a/pkg/workflow/github_token_test.go b/pkg/workflow/github_token_test.go index 24f89fe9651..650d8edacc2 100644 --- a/pkg/workflow/github_token_test.go +++ b/pkg/workflow/github_token_test.go @@ -8,34 +8,25 @@ import ( func TestGetEffectiveGitHubToken(t *testing.T) { tests := []struct { - name string - customToken string - toplevelToken string - expected string + name string + customToken string + expected string }{ { - name: "custom token has highest precedence", - customToken: "${{ secrets.CUSTOM_TOKEN }}", - toplevelToken: "${{ secrets.TOPLEVEL_TOKEN }}", - expected: "${{ secrets.CUSTOM_TOKEN }}", + name: "custom token has highest precedence", + customToken: "${{ secrets.CUSTOM_TOKEN }}", + expected: "${{ secrets.CUSTOM_TOKEN }}", }, { - name: "toplevel token used when no custom token", - customToken: "", - toplevelToken: "${{ secrets.TOPLEVEL_TOKEN }}", - expected: "${{ secrets.TOPLEVEL_TOKEN }}", - }, - { - name: "default fallback includes GH_AW_GITHUB_MCP_SERVER_TOKEN (for MCP and tools)", - customToken: "", - toplevelToken: "", - expected: "${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", + name: "default fallback includes GH_AW_GITHUB_MCP_SERVER_TOKEN (for MCP and tools)", + customToken: "", + expected: "${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := getEffectiveGitHubToken(tt.customToken, tt.toplevelToken) + result := getEffectiveGitHubToken(tt.customToken) if result != tt.expected { t.Errorf("getEffectiveGitHubToken() = %q, want %q", result, tt.expected) } @@ -45,34 +36,25 @@ func TestGetEffectiveGitHubToken(t *testing.T) { func TestGetEffectiveSafeOutputGitHubToken(t *testing.T) { tests := []struct { - name string - customToken string - toplevelToken string - expected string + name string + customToken string + expected string }{ { - name: "custom token has highest precedence", - customToken: "${{ secrets.CUSTOM_TOKEN }}", - toplevelToken: "${{ secrets.TOPLEVEL_TOKEN }}", - expected: "${{ secrets.CUSTOM_TOKEN }}", - }, - { - name: "toplevel token used when no custom token", - customToken: "", - toplevelToken: "${{ secrets.TOPLEVEL_TOKEN }}", - expected: "${{ secrets.TOPLEVEL_TOKEN }}", + name: "custom token has highest precedence", + customToken: "${{ secrets.CUSTOM_TOKEN }}", + expected: "${{ secrets.CUSTOM_TOKEN }}", }, { - name: "default fallback includes GH_AW_GITHUB_TOKEN (safe outputs chain)", - customToken: "", - toplevelToken: "", - expected: "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", + name: "default fallback includes GH_AW_GITHUB_TOKEN (safe outputs chain)", + customToken: "", + expected: "${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := getEffectiveSafeOutputGitHubToken(tt.customToken, tt.toplevelToken) + result := getEffectiveSafeOutputGitHubToken(tt.customToken) if result != tt.expected { t.Errorf("getEffectiveSafeOutputGitHubToken() = %q, want %q", result, tt.expected) } @@ -82,34 +64,25 @@ func TestGetEffectiveSafeOutputGitHubToken(t *testing.T) { func TestGetEffectiveCopilotGitHubToken(t *testing.T) { tests := []struct { - name string - customToken string - toplevelToken string - expected string + name string + customToken string + expected string }{ { - name: "custom token has highest precedence", - customToken: "${{ secrets.CUSTOM_COPILOT_TOKEN }}", - toplevelToken: "${{ secrets.TOPLEVEL_TOKEN }}", - expected: "${{ secrets.CUSTOM_COPILOT_TOKEN }}", + name: "custom token has highest precedence", + customToken: "${{ secrets.CUSTOM_COPILOT_TOKEN }}", + expected: "${{ secrets.CUSTOM_COPILOT_TOKEN }}", }, { - name: "toplevel token used when no custom token", - customToken: "", - toplevelToken: "${{ secrets.TOPLEVEL_TOKEN }}", - expected: "${{ secrets.TOPLEVEL_TOKEN }}", - }, - { - name: "default fallback for Copilot includes multiple tokens", - customToken: "", - toplevelToken: "", - expected: "${{ secrets.COPILOT_GITHUB_TOKEN || secrets.GH_AW_GITHUB_TOKEN }}", + name: "default fallback for Copilot", + customToken: "", + expected: "${{ secrets.COPILOT_GITHUB_TOKEN }}", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := getEffectiveCopilotGitHubToken(tt.customToken, tt.toplevelToken) + result := getEffectiveCopilotGitHubToken(tt.customToken) if result != tt.expected { t.Errorf("getEffectiveCopilotGitHubToken() = %q, want %q", result, tt.expected) } @@ -119,34 +92,25 @@ func TestGetEffectiveCopilotGitHubToken(t *testing.T) { func TestGetEffectiveAgentGitHubToken(t *testing.T) { tests := []struct { - name string - customToken string - toplevelToken string - expected string + name string + customToken string + expected string }{ { - name: "custom token has highest precedence", - customToken: "${{ secrets.CUSTOM_AGENT_TOKEN }}", - toplevelToken: "${{ secrets.TOP_LEVEL_TOKEN }}", - expected: "${{ secrets.CUSTOM_AGENT_TOKEN }}", - }, - { - name: "toplevel token when custom is empty", - customToken: "", - toplevelToken: "${{ secrets.TOP_LEVEL_TOKEN }}", - expected: "${{ secrets.TOP_LEVEL_TOKEN }}", + name: "custom token has highest precedence", + customToken: "${{ secrets.CUSTOM_AGENT_TOKEN }}", + expected: "${{ secrets.CUSTOM_AGENT_TOKEN }}", }, { - name: "default fallback chain for agent operations", - customToken: "", - toplevelToken: "", - expected: "${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", + name: "default fallback chain for agent operations", + customToken: "", + expected: "${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := getEffectiveAgentGitHubToken(tt.customToken, tt.toplevelToken) + result := getEffectiveAgentGitHubToken(tt.customToken) if result != tt.expected { t.Errorf("getEffectiveAgentGitHubToken() = %q, want %q", result, tt.expected) } diff --git a/pkg/workflow/http_mcp_env_vars_test.go b/pkg/workflow/http_mcp_env_vars_test.go index be5cbb8dcc3..aa4ea9968a4 100644 --- a/pkg/workflow/http_mcp_env_vars_test.go +++ b/pkg/workflow/http_mcp_env_vars_test.go @@ -26,9 +26,7 @@ func TestCollectMCPEnvironmentVariables_HTTPMCPWithSecrets(t *testing.T) { } mcpTools := []string{"github", "tavily"} - workflowData := &WorkflowData{ - GitHubToken: "${{ secrets.GITHUB_TOKEN }}", - } + workflowData := &WorkflowData{} hasAgenticWorkflows := false envVars := collectMCPEnvironmentVariables(tools, mcpTools, workflowData, hasAgenticWorkflows) diff --git a/pkg/workflow/imports.go b/pkg/workflow/imports.go index 3e0b1dffdbb..c5258969b51 100644 --- a/pkg/workflow/imports.go +++ b/pkg/workflow/imports.go @@ -624,9 +624,6 @@ func mergeSafeOutputConfig(result *SafeOutputsConfig, config map[string]any, c * if len(result.Env) == 0 && len(importedConfig.Env) > 0 { result.Env = importedConfig.Env } - if result.GitHubToken == "" && importedConfig.GitHubToken != "" { - result.GitHubToken = importedConfig.GitHubToken - } if result.MaximumPatchSize == 0 && importedConfig.MaximumPatchSize > 0 { result.MaximumPatchSize = importedConfig.MaximumPatchSize } diff --git a/pkg/workflow/mcp_environment.go b/pkg/workflow/mcp_environment.go index bbd749fa872..7a5116bbd60 100644 --- a/pkg/workflow/mcp_environment.go +++ b/pkg/workflow/mcp_environment.go @@ -80,7 +80,7 @@ func collectMCPEnvironmentVariables(tools map[string]any, mcpTools []string, wor } else { // Otherwise, use custom token or default fallback customGitHubToken := getGitHubToken(githubTool) - effectiveToken := getEffectiveGitHubToken(customGitHubToken, workflowData.GitHubToken) + effectiveToken := getEffectiveGitHubToken(customGitHubToken) envVars["GITHUB_MCP_SERVER_TOKEN"] = effectiveToken } diff --git a/pkg/workflow/mcp_setup_generator.go b/pkg/workflow/mcp_setup_generator.go index 24d1fbb0839..28999450a1c 100644 --- a/pkg/workflow/mcp_setup_generator.go +++ b/pkg/workflow/mcp_setup_generator.go @@ -165,8 +165,8 @@ func (c *Compiler) generateMCPSetup(yaml *strings.Builder, tools map[string]any, // Only install gh-aw if needed and not already provided by imports if hasAgenticWorkflows && !hasGhAwImport { - // Use effective token with precedence: top-level github-token > default - effectiveToken := getEffectiveGitHubToken("", workflowData.GitHubToken) + // Use effective token with precedence: custom > default + effectiveToken := getEffectiveGitHubToken("") yaml.WriteString(" - name: Install gh-aw extension\n") yaml.WriteString(" env:\n") diff --git a/pkg/workflow/plugin_compilation_test.go b/pkg/workflow/plugin_compilation_test.go index 7cfb30deabc..e490074c455 100644 --- a/pkg/workflow/plugin_compilation_test.go +++ b/pkg/workflow/plugin_compilation_test.go @@ -269,14 +269,13 @@ func TestPluginCompilationTokenPrecedence(t *testing.T) { description string }{ { - name: "Object github-token overrides top-level", + name: "Plugin-specific github-token used", workflow: `--- engine: copilot on: workflow_dispatch permissions: issues: read pull-requests: read -github-token: ${{ secrets.TOPLEVEL_TOKEN }} plugins: repos: - github/plugin1 @@ -286,25 +285,7 @@ plugins: Test token precedence `, expectedToken: "GITHUB_TOKEN: ${{ secrets.PLUGINS_SPECIFIC_TOKEN }}", - description: "plugins.github-token should override top-level github-token", - }, - { - name: "Top-level token used when no plugin token", - workflow: `--- -engine: copilot -on: workflow_dispatch -permissions: - issues: read - pull-requests: read -github-token: ${{ secrets.TOPLEVEL_TOKEN }} -plugins: - - github/plugin1 ---- - -Test top-level token -`, - expectedToken: "GITHUB_TOKEN: ${{ secrets.TOPLEVEL_TOKEN }}", - description: "top-level github-token should be used when no plugins.github-token", + description: "plugins.github-token should be used when specified", }, { name: "Cascading fallback when no tokens specified", diff --git a/pkg/workflow/plugin_installation_test.go b/pkg/workflow/plugin_installation_test.go index e9dcb071cce..6c5ede6049d 100644 --- a/pkg/workflow/plugin_installation_test.go +++ b/pkg/workflow/plugin_installation_test.go @@ -241,7 +241,7 @@ func TestPluginTokenCascading(t *testing.T) { expectedToken: "${{ secrets.GH_AW_PLUGINS_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}", }, { - name: "Frontmatter github-token provided", + name: "Plugins config token provided", customToken: "${{ secrets.MY_GITHUB_TOKEN }}", expectedToken: "${{ secrets.MY_GITHUB_TOKEN }}", }, diff --git a/pkg/workflow/pr.go b/pkg/workflow/pr.go index 87dff509c5b..8f5d51621d6 100644 --- a/pkg/workflow/pr.go +++ b/pkg/workflow/pr.go @@ -42,12 +42,12 @@ func (c *Compiler) generatePRReadyForReviewCheckout(yaml *strings.Builder, data fmt.Fprintf(yaml, " uses: %s\n", GetActionPin("actions/github-script")) // Add env section with GH_TOKEN for gh CLI - // Use safe-outputs github-token if available, otherwise top-level token + // Use safe-outputs github-token if available, otherwise default token safeOutputsToken := "" if data.SafeOutputs != nil && data.SafeOutputs.GitHubToken != "" { safeOutputsToken = data.SafeOutputs.GitHubToken } - effectiveToken := getEffectiveGitHubToken(safeOutputsToken, data.GitHubToken) + effectiveToken := getEffectiveGitHubToken(safeOutputsToken) prLog.Print("PR checkout step configured with GitHub token") yaml.WriteString(" env:\n") fmt.Fprintf(yaml, " GH_TOKEN: %s\n", effectiveToken) diff --git a/pkg/workflow/safe_outputs_env.go b/pkg/workflow/safe_outputs_env.go index 4ae1dc1fdb4..aaaf2ae364e 100644 --- a/pkg/workflow/safe_outputs_env.go +++ b/pkg/workflow/safe_outputs_env.go @@ -221,7 +221,7 @@ func (c *Compiler) addCustomSafeOutputEnvVars(steps *[]string, data *WorkflowDat } // addSafeOutputGitHubTokenForConfig adds github-token to the with section, preferring per-config token over global -// Uses precedence: config token > safe-outputs global github-token > top-level github-token > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN +// Uses precedence: config token > safe-outputs global github-token > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN func (c *Compiler) addSafeOutputGitHubTokenForConfig(steps *[]string, data *WorkflowData, configToken string) { var safeOutputsToken string if data.SafeOutputs != nil { @@ -234,13 +234,19 @@ func (c *Compiler) addSafeOutputGitHubTokenForConfig(steps *[]string, data *Work return } - // Get effective token using double precedence: config > safe-outputs, then > top-level > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN - effectiveToken := getEffectiveSafeOutputGitHubToken(configToken, getEffectiveSafeOutputGitHubToken(safeOutputsToken, data.GitHubToken)) + // Choose the first non-empty custom token for precedence + effectiveCustomToken := configToken + if effectiveCustomToken == "" { + effectiveCustomToken = safeOutputsToken + } + + // Get effective token + effectiveToken := getEffectiveSafeOutputGitHubToken(effectiveCustomToken) *steps = append(*steps, fmt.Sprintf(" github-token: %s\n", effectiveToken)) } // addSafeOutputCopilotGitHubTokenForConfig adds github-token to the with section for Copilot-related operations -// Uses precedence: config token > safe-outputs global github-token > top-level github-token > COPILOT_GITHUB_TOKEN > GH_AW_GITHUB_TOKEN (legacy) +// Uses precedence: config token > safe-outputs global github-token > COPILOT_GITHUB_TOKEN func (c *Compiler) addSafeOutputCopilotGitHubTokenForConfig(steps *[]string, data *WorkflowData, configToken string) { var safeOutputsToken string if data.SafeOutputs != nil { @@ -253,13 +259,19 @@ func (c *Compiler) addSafeOutputCopilotGitHubTokenForConfig(steps *[]string, dat return } - // Get effective token using double precedence: config > safe-outputs, then > top-level > Copilot default - effectiveToken := getEffectiveCopilotGitHubToken(configToken, getEffectiveCopilotGitHubToken(safeOutputsToken, data.GitHubToken)) + // Choose the first non-empty custom token for precedence + effectiveCustomToken := configToken + if effectiveCustomToken == "" { + effectiveCustomToken = safeOutputsToken + } + + // Get effective token + effectiveToken := getEffectiveCopilotGitHubToken(effectiveCustomToken) *steps = append(*steps, fmt.Sprintf(" github-token: %s\n", effectiveToken)) } // addSafeOutputAgentGitHubTokenForConfig adds github-token to the with section for agent assignment operations -// Uses precedence: config token > safe-outputs token > workflow token > GH_AW_AGENT_TOKEN || GH_AW_GITHUB_TOKEN || GITHUB_TOKEN +// Uses precedence: config token > safe-outputs token > GH_AW_AGENT_TOKEN || GH_AW_GITHUB_TOKEN || GITHUB_TOKEN // This is specifically for assign-to-agent operations which require elevated permissions. func (c *Compiler) addSafeOutputAgentGitHubTokenForConfig(steps *[]string, data *WorkflowData, configToken string) { // If app is configured, use app token @@ -274,8 +286,14 @@ func (c *Compiler) addSafeOutputAgentGitHubTokenForConfig(steps *[]string, data safeOutputsToken = data.SafeOutputs.GitHubToken } - // Get effective token using full precedence chain: config > safe-outputs > workflow > GH_AW_AGENT_TOKEN fallback - effectiveToken := getEffectiveAgentGitHubToken(configToken, getEffectiveAgentGitHubToken(safeOutputsToken, data.GitHubToken)) + // Choose the first non-empty custom token for precedence + effectiveCustomToken := configToken + if effectiveCustomToken == "" { + effectiveCustomToken = safeOutputsToken + } + + // Get effective token + effectiveToken := getEffectiveAgentGitHubToken(effectiveCustomToken) *steps = append(*steps, fmt.Sprintf(" github-token: %s\n", effectiveToken)) } diff --git a/pkg/workflow/safe_outputs_handler_manager_token_test.go b/pkg/workflow/safe_outputs_handler_manager_token_test.go index f62f8f2c662..5a8c1488a52 100644 --- a/pkg/workflow/safe_outputs_handler_manager_token_test.go +++ b/pkg/workflow/safe_outputs_handler_manager_token_test.go @@ -139,11 +139,6 @@ func TestHandlerManagerProjectGitHubTokenEnvVar(t *testing.T) { SafeOutputs: compiler.extractSafeOutputsConfig(tt.frontmatter), } - // Set top-level github-token if present in frontmatter - if githubToken, ok := tt.frontmatter["github-token"].(string); ok { - workflowData.GitHubToken = githubToken - } - // Build the handler manager step steps := compiler.buildHandlerManagerStep(workflowData) yamlStr := strings.Join(steps, "") diff --git a/pkg/workflow/safe_outputs_steps.go b/pkg/workflow/safe_outputs_steps.go index b56934c0a9e..49d0d39aac1 100644 --- a/pkg/workflow/safe_outputs_steps.go +++ b/pkg/workflow/safe_outputs_steps.go @@ -63,35 +63,33 @@ func (c *Compiler) buildCustomActionStep(data *WorkflowData, config GitHubScript // addCustomActionGitHubToken adds a GitHub token as action input. // The token precedence depends on the tokenType flags: -// - UseAgentToken: customToken > SafeOutputs.GitHubToken > data.GitHubToken > GH_AW_AGENT_TOKEN || GH_AW_GITHUB_TOKEN || GITHUB_TOKEN -// - UseCopilotToken: customToken > SafeOutputs.GitHubToken > data.GitHubToken > COPILOT_GITHUB_TOKEN || GH_AW_GITHUB_TOKEN -// - Default: customToken > SafeOutputs.GitHubToken > data.GitHubToken > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN +// - UseAgentToken: customToken > SafeOutputs.GitHubToken > GH_AW_AGENT_TOKEN || GH_AW_GITHUB_TOKEN || GITHUB_TOKEN +// - UseCopilotToken: customToken > SafeOutputs.GitHubToken > COPILOT_GITHUB_TOKEN +// - Default: customToken > SafeOutputs.GitHubToken > GH_AW_GITHUB_TOKEN || GITHUB_TOKEN func (c *Compiler) addCustomActionGitHubToken(steps *[]string, data *WorkflowData, customToken string, useAgentToken, useCopilotToken bool) { var token string + // Get safe-outputs level token + var safeOutputsToken string + if data.SafeOutputs != nil { + safeOutputsToken = data.SafeOutputs.GitHubToken + } + + // Choose the first non-empty custom token for precedence + effectiveCustomToken := customToken + if effectiveCustomToken == "" { + effectiveCustomToken = safeOutputsToken + } + // Agent token mode: use full precedence chain for agent assignment if useAgentToken { - var safeOutputsToken string - if data.SafeOutputs != nil { - safeOutputsToken = data.SafeOutputs.GitHubToken - } - // Precedence: customToken > safeOutputsToken > data.GitHubToken > default Agent fallback chain - token = getEffectiveAgentGitHubToken(customToken, getEffectiveAgentGitHubToken(safeOutputsToken, data.GitHubToken)) + token = getEffectiveAgentGitHubToken(effectiveCustomToken) } else if useCopilotToken { // Copilot mode: use getEffectiveCopilotGitHubToken with safe-outputs token precedence - var safeOutputsToken string - if data.SafeOutputs != nil { - safeOutputsToken = data.SafeOutputs.GitHubToken - } - // Precedence: customToken > safeOutputsToken > data.GitHubToken > default Copilot fallback - token = getEffectiveCopilotGitHubToken(customToken, getEffectiveCopilotGitHubToken(safeOutputsToken, data.GitHubToken)) + token = getEffectiveCopilotGitHubToken(effectiveCustomToken) } else { - // Standard mode: use safe output token chain (data.GitHubToken, then GITHUB_TOKEN) - var safeOutputsToken string - if data.SafeOutputs != nil { - safeOutputsToken = data.SafeOutputs.GitHubToken - } - token = getEffectiveSafeOutputGitHubToken(customToken, getEffectiveSafeOutputGitHubToken(safeOutputsToken, data.GitHubToken)) + // Standard mode: use safe output token chain + token = getEffectiveSafeOutputGitHubToken(effectiveCustomToken) } *steps = append(*steps, fmt.Sprintf(" token: %s\n", token)) From 24a09995eefa583cacd8499e85cf6ad20de57685 Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 17 Feb 2026 16:58:17 +0000 Subject: [PATCH 2/5] remove top level github token --- docs/src/content/docs/reference/frontmatter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md index 5790327aa80..152334c27bf 100644 --- a/docs/src/content/docs/reference/frontmatter.md +++ b/docs/src/content/docs/reference/frontmatter.md @@ -22,7 +22,7 @@ tools: ## Frontmatter Elements -The frontmatter combines standard GitHub Actions properties (`on`, `permissions`, `run-name`, `runs-on`, `timeout-minutes`, `concurrency`, `env`, `environment`, `container`, `services`, `if`, `steps`, `cache`) with GitHub Agentic Workflows-specific elements (`description`, `source`, `github-token`, `imports`, `engine`, `strict`, `roles`, `features`, `plugins`, `runtimes`, `safe-inputs`, `safe-outputs`, `network`, `tools`). +The frontmatter combines standard GitHub Actions properties (`on`, `permissions`, `run-name`, `runs-on`, `timeout-minutes`, `concurrency`, `env`, `environment`, `container`, `services`, `if`, `steps`, `cache`) with GitHub Agentic Workflows-specific elements (`description`, `source`, `imports`, `engine`, `strict`, `roles`, `features`, `plugins`, `runtimes`, `safe-inputs`, `safe-outputs`, `network`, `tools`). Tool configurations (such as `bash`, `edit`, `github`, `web-fetch`, `web-search`, `playwright`, `cache-memory`, and custom [Model Context Protocol](/gh-aw/reference/glossary/#mcp-model-context-protocol) (MCP) [servers](/gh-aw/reference/glossary/#mcp-server)) are specified under the `tools:` key. Custom inline tools can be defined with the [`safe-inputs:`](/gh-aw/reference/safe-inputs/) (custom tools defined inline) key. See [Tools](/gh-aw/reference/tools/) and [Safe Inputs](/gh-aw/reference/safe-inputs/) for complete documentation. From 9cab60dd714a31163f8563e72f3dcb287fd24cbb Mon Sep 17 00:00:00 2001 From: Don Syme Date: Tue, 17 Feb 2026 18:48:04 +0000 Subject: [PATCH 3/5] adjust terminology --- .github/aw/agentic-chat.md | 4 +- .github/aw/debug-agentic-workflow.md | 2 +- .github/aw/github-agentic-workflows.md | 4 +- .../workflows/copilot-agent-analysis.lock.yml | 6 +- .github/workflows/copilot-agent-analysis.md | 4 +- .github/workflows/copilot-pr-merged-report.md | 6 +- .../copilot-session-insights.lock.yml | 8 +-- .github/workflows/copilot-session-insights.md | 10 +-- .../daily-mcp-concurrency-analysis.lock.yml | 6 +- .../daily-mcp-concurrency-analysis.md | 2 +- .../daily-safe-outputs-conformance.md | 4 +- .github/workflows/issue-monster.lock.yml | 12 ++-- .github/workflows/issue-monster.md | 20 +++--- .github/workflows/plan.md | 4 +- .github/workflows/poem-bot.lock.yml | 6 +- .../prompt-clustering-analysis.lock.yml | 6 +- .../workflows/prompt-clustering-analysis.md | 2 +- .../workflows/repository-quality-improver.md | 18 ++--- .../workflows/shared/copilot-pr-data-fetch.md | 2 +- .../shared/copilot-session-data-fetch.md | 8 +-- .../workflows/shared/pr-data-safe-input.md | 2 +- .../shared/session-analysis-charts.md | 4 +- .../shared/session-analysis-strategies.md | 2 +- .github/workflows/static-analysis-report.md | 2 +- .github/workflows/workflow-generator.lock.yml | 10 +-- .github/workflows/workflow-generator.md | 8 +-- AGENTS.md | 4 +- CHANGELOG.md | 8 +-- actions/setup/js/assign_agent_helpers.cjs | 4 +- actions/setup/js/safe_outputs_tools.json | 8 +-- actions/setup/js/types/safe-outputs.d.ts | 2 +- ...3-meet-the-workflows-advanced-analytics.md | 6 +- ...-13-meet-the-workflows-issue-management.md | 4 +- docs/src/content/docs/reference/auth.mdx | 37 ++++------ docs/src/content/docs/reference/faq.md | 6 +- .../docs/reference/frontmatter-full.md | 10 +-- .../reference/safe-outputs-specification.md | 6 +- .../content/docs/reference/safe-outputs.md | 10 +-- docs/src/content/docs/setup/cli.md | 2 +- pkg/cli/commands.go | 2 +- pkg/cli/copilot_agent.go | 34 ++++----- pkg/cli/copilot_agent_test.go | 10 +-- pkg/cli/interactive.go | 2 +- pkg/cli/logs_metrics.go | 8 +-- pkg/cli/logs_parsing_engines.go | 6 +- pkg/cli/workflows/test-assign-to-agent.md | 6 +- .../test-copilot-create-agent-session.md | 2 +- pkg/parser/schemas/main_workflow_schema.json | 10 +-- pkg/workflow/compiler_safe_outputs_core.go | 24 +++---- .../compiler_safe_outputs_specialized.go | 30 ++++---- pkg/workflow/compiler_safe_outputs_steps.go | 4 +- .../compiler_safe_outputs_steps_test.go | 72 +++++++++---------- pkg/workflow/compiler_types.go | 2 +- pkg/workflow/copilot_participant_steps.go | 4 +- pkg/workflow/create_agent_session.go | 28 ++++---- pkg/workflow/create_issue.go | 8 +-- .../custom_action_copilot_token_test.go | 10 +-- pkg/workflow/github_token.go | 8 +-- pkg/workflow/github_token_test.go | 8 +-- pkg/workflow/js/safe_outputs_tools.json | 8 +-- pkg/workflow/mcp_playwright_config.go | 2 +- pkg/workflow/model_env_vars_test.go | 2 +- pkg/workflow/notify_comment.go | 12 ++-- pkg/workflow/permissions_factory.go | 2 +- pkg/workflow/safe_output_helpers_test.go | 16 ++--- pkg/workflow/safe_outputs_env.go | 4 +- pkg/workflow/safe_outputs_jobs.go | 54 +++++++------- pkg/workflow/safe_outputs_steps.go | 56 +++++++-------- pkg/workflow/safe_outputs_test.go | 6 +- research/blog-research/BLOG-RESEARCH.md | 20 +++--- schemas/agent-output.json | 2 +- scratchpad/end-to-end-feature-testing.md | 6 +- scratchpad/metrics-glossary.md | 6 +- scratchpad/safe-outputs-specification.md | 4 +- scratchpad/security_review.md | 2 +- scratchpad/template-injection-prevention.md | 2 +- scripts/changeset.js | 2 +- skills/gh-agent-session/SKILL.md | 4 +- skills/gh-agent-task/SKILL.md | 4 +- .../SKILL.md | 10 +-- 80 files changed, 379 insertions(+), 392 deletions(-) diff --git a/.github/aw/agentic-chat.md b/.github/aw/agentic-chat.md index a336ea9aa91..79b1f92fc9b 100644 --- a/.github/aw/agentic-chat.md +++ b/.github/aw/agentic-chat.md @@ -1,11 +1,11 @@ --- name: agentic-chat -description: AI assistant for creating clear, actionable task descriptions for GitHub Copilot agents +description: AI assistant for creating clear, actionable task descriptions for GitHub Copilot coding agent --- # Agentic Task Description Assistant -You are an AI assistant specialized in helping users create clear, actionable task descriptions for GitHub Copilot agents that work with GitHub Agentic Workflows (gh-aw). +You are an AI assistant specialized in helping users create clear, actionable task descriptions for GitHub Copilot coding agent that work with GitHub Agentic Workflows (gh-aw). ## Required Knowledge diff --git a/.github/aw/debug-agentic-workflow.md b/.github/aw/debug-agentic-workflow.md index 8dbe27ca05c..d268b065179 100644 --- a/.github/aw/debug-agentic-workflow.md +++ b/.github/aw/debug-agentic-workflow.md @@ -66,7 +66,7 @@ Report back with specific findings and actionable fixes. > [!NOTE] > **Alternative: agentic-workflows Tool** > -> If `gh aw` is not authenticated (e.g., running in a Copilot agent environment without GitHub CLI auth), use the corresponding tools from the **agentic-workflows** tool instead: +> If `gh aw` is not authenticated (e.g., running in a Copilot coding agent environment without GitHub CLI auth), use the corresponding tools from the **agentic-workflows** tool instead: > - `status` tool → equivalent to `gh aw status` > - `compile` tool → equivalent to `gh aw compile` > - `logs` tool → equivalent to `gh aw logs` diff --git a/.github/aw/github-agentic-workflows.md b/.github/aw/github-agentic-workflows.md index 6c1d5b35379..796bc3b9dda 100644 --- a/.github/aw/github-agentic-workflows.md +++ b/.github/aw/github-agentic-workflows.md @@ -736,7 +736,7 @@ The YAML frontmatter supports these fields: max: 10 # Optional: max autofixes (default: 10) ``` Provides automated fixes for code scanning alerts. - - `create-agent-session:` - Create GitHub Copilot agent sessions + - `create-agent-session:` - Create GitHub Copilot coding agent sessions ```yaml safe-outputs: create-agent-session: @@ -744,7 +744,7 @@ The YAML frontmatter supports these fields: target-repo: "owner/repo" # Optional: cross-repository ``` Requires PAT as `COPILOT_GITHUB_TOKEN`. Note: `create-agent-task` is deprecated (use `create-agent-session`). - - `assign-to-agent:` - Assign Copilot agents to issues + - `assign-to-agent:` - Assign Copilot coding agent to issues ```yaml safe-outputs: assign-to-agent: diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 6c9a4979b9c..69c4730313c 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -21,7 +21,7 @@ # # For more information: https://github.github.com/gh-aw/introduction/overview/ # -# Analyzes GitHub Copilot agent usage patterns in pull requests to provide insights on agent effectiveness and behavior +# Analyzes GitHub Copilot coding agent usage patterns in pull requests to provide insights on agent effectiveness and behavior # # Resolved workflow manifest: # Imports: @@ -30,7 +30,7 @@ # - shared/mood.md # - shared/reporting.md # -# frontmatter-hash: 7ab09aa2c72d1dc010110d7ac8ad24c689601553f85c0c0554d6b7b897e9a090 +# frontmatter-hash: 49e233a6fddc68b01bfb552844d10705384860956cebc90df11ae53e16d11dc9 name: "Copilot Agent PR Analysis" "on": @@ -1119,7 +1119,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: WORKFLOW_NAME: "Copilot Agent PR Analysis" - WORKFLOW_DESCRIPTION: "Analyzes GitHub Copilot agent usage patterns in pull requests to provide insights on agent effectiveness and behavior" + WORKFLOW_DESCRIPTION: "Analyzes GitHub Copilot coding agent usage patterns in pull requests to provide insights on agent effectiveness and behavior" HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | diff --git a/.github/workflows/copilot-agent-analysis.md b/.github/workflows/copilot-agent-analysis.md index 83e5b938a76..6eaa3e4320e 100644 --- a/.github/workflows/copilot-agent-analysis.md +++ b/.github/workflows/copilot-agent-analysis.md @@ -1,6 +1,6 @@ --- name: Copilot Agent PR Analysis -description: Analyzes GitHub Copilot agent usage patterns in pull requests to provide insights on agent effectiveness and behavior +description: Analyzes GitHub Copilot coding agent usage patterns in pull requests to provide insights on agent effectiveness and behavior on: schedule: # Every day at 6pm UTC @@ -466,7 +466,7 @@ The "Agent Task Texts" section should include a table showing all PRs created in ### No PRs in Last 24 Hours If no PRs were created by Copilot in the last 24 hours: -- Create a minimal discussion: "No Copilot agent activity in the last 24 hours." +- Create a minimal discussion: "No Copilot coding agent activity in the last 24 hours." - Update repo memory with zero counts - Keep it to 2-3 sentences max diff --git a/.github/workflows/copilot-pr-merged-report.md b/.github/workflows/copilot-pr-merged-report.md index b9742d0d31c..e7693735068 100644 --- a/.github/workflows/copilot-pr-merged-report.md +++ b/.github/workflows/copilot-pr-merged-report.md @@ -45,7 +45,7 @@ timeout-minutes: 10 # Daily Copilot PR Merged Report -You are an AI analytics agent that generates daily reports on GitHub Copilot agent pull requests that were **merged** in the last 24 hours. +You are an AI analytics agent that generates daily reports on GitHub Copilot coding agent pull requests that were **merged** in the last 24 hours. ## Mission @@ -82,7 +82,7 @@ safeinputs-gh with args: "pr list --repo ${{ github.repository }} --search \"hea ``` This searches for: -- PRs from branches starting with `copilot/` (Copilot agent PRs) +- PRs from branches starting with `copilot/` (Copilot coding agent PRs) - PRs that are merged - PRs merged in the last 24 hours - Returns: PR number, title, merge timestamp, additions, deletions, files changed, URL @@ -283,7 +283,7 @@ If no Copilot PRs were merged in the last 24 hours: ```markdown # 🤖 Daily Copilot PR Merged Report - [DATE] -No Copilot agent pull requests were merged in the last 24 hours. +No Copilot coding agent pull requests were merged in the last 24 hours. --- _Generated by Copilot PR Merged Report (Run: [${{ github.run_id }}](...))_ diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index d6497e846c2..a1e75d7d4c8 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -21,7 +21,7 @@ # # For more information: https://github.github.com/gh-aw/introduction/overview/ # -# Analyzes GitHub Copilot agent sessions to provide detailed insights on usage patterns, success rates, and performance metrics +# Analyzes GitHub Copilot coding agent sessions to provide detailed insights on usage patterns, success rates, and performance metrics # # Resolved workflow manifest: # Imports: @@ -33,7 +33,7 @@ # - shared/session-analysis-charts.md # - shared/session-analysis-strategies.md # -# frontmatter-hash: 1b2864370d65c60ed768cb2e794d2b20256ec84f3ce347aca33dbbd2e8032bdd +# frontmatter-hash: 750804c6a2a89dc635b4c6e1216950672e3620fb95c1202f3aa34b1d798cfcca name: "Copilot Session Insights" "on": @@ -346,7 +346,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} name: Fetch Copilot session data - run: "# Create output directories\nmkdir -p /tmp/gh-aw/session-data\nmkdir -p /tmp/gh-aw/session-data/logs\nmkdir -p /tmp/gh-aw/cache-memory\n\n# Get today's date for cache identification\nTODAY=$(date '+%Y-%m-%d')\nCACHE_DIR=\"/tmp/gh-aw/cache-memory\"\n\n# Check if cached data exists from today\nif [ -f \"$CACHE_DIR/copilot-sessions-${TODAY}.json\" ] && [ -s \"$CACHE_DIR/copilot-sessions-${TODAY}.json\" ]; then\n echo \"✓ Found cached session data from ${TODAY}\"\n cp \"$CACHE_DIR/copilot-sessions-${TODAY}.json\" /tmp/gh-aw/session-data/sessions-list.json\n \n # Regenerate schema if missing\n if [ ! -f \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\" ]; then\n /tmp/gh-aw/jqschema.sh < /tmp/gh-aw/session-data/sessions-list.json > \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\"\n fi\n cp \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\" /tmp/gh-aw/session-data/sessions-schema.json\n \n # Restore cached log files if they exist\n if [ -d \"$CACHE_DIR/session-logs-${TODAY}\" ]; then\n echo \"✓ Found cached session logs from ${TODAY}\"\n cp -r \"$CACHE_DIR/session-logs-${TODAY}\"/* /tmp/gh-aw/session-data/logs/ 2>/dev/null || true\n echo \"Restored $(find /tmp/gh-aw/session-data/logs -type f | wc -l) session log files from cache\"\n fi\n \n echo \"Using cached data from ${TODAY}\"\n echo \"Total sessions in cache: $(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\"\nelse\n echo \"⬇ Downloading fresh session data...\"\n \n # Calculate date 30 days ago\n DATE_30_DAYS_AGO=$(date -d '30 days ago' '+%Y-%m-%d' 2>/dev/null || date -v-30d '+%Y-%m-%d')\n\n # Search for workflow runs from copilot/* branches\n # This fetches GitHub Copilot agent task runs by searching for workflow runs on copilot/* branches\n echo \"Fetching Copilot agent workflow runs from the last 30 days...\"\n \n # Get workflow runs from copilot/* branches\n gh api \"repos/${{ github.repository }}/actions/runs\" \\\n --paginate \\\n --jq \".workflow_runs[] | select(.head_branch | startswith(\\\"copilot/\\\")) | select(.created_at >= \\\"${DATE_30_DAYS_AGO}\\\") | {id, name, head_branch, created_at, updated_at, status, conclusion, html_url}\" \\\n | jq -s '.[0:50]' \\\n > /tmp/gh-aw/session-data/sessions-list.json\n\n # Generate schema for reference\n /tmp/gh-aw/jqschema.sh < /tmp/gh-aw/session-data/sessions-list.json > /tmp/gh-aw/session-data/sessions-schema.json\n\n # Download conversation logs using gh agent-task command (limit to first 50)\n SESSION_COUNT=$(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\n echo \"Downloading conversation logs for $SESSION_COUNT sessions...\"\n \n # Use gh agent-task to fetch session logs with conversation transcripts\n # Extract session numbers from head_branch (format: copilot/issue-123 or copilot/task-456)\n # The number is the issue/task/PR number that the gh agent-task command uses\n jq -r '.[].head_branch' /tmp/gh-aw/session-data/sessions-list.json | while read -r branch; do\n if [ -n \"$branch\" ]; then\n # Extract number from branch name (e.g., copilot/issue-123 -> 123)\n # This is the session identifier used by gh agent-task\n session_number=$(echo \"$branch\" | sed 's/copilot\\///' | sed 's/[^0-9]//g')\n \n if [ -n \"$session_number\" ]; then\n echo \"Downloading conversation log for session #$session_number (branch: $branch)\"\n \n # Use gh agent-task view --log to get conversation transcript\n # This contains the agent's internal monologue, tool calls, and reasoning\n gh agent-task view --repo \"${{ github.repository }}\" \"$session_number\" --log \\\n > \"/tmp/gh-aw/session-data/logs/${session_number}-conversation.txt\" 2>&1 || {\n echo \"Warning: Could not fetch conversation log for session #$session_number\"\n # If gh agent-task fails, fall back to downloading GitHub Actions logs\n # This ensures we have some data even if agent-task command is unavailable\n run_id=$(jq -r \".[] | select(.head_branch == \\\"$branch\\\") | .id\" /tmp/gh-aw/session-data/sessions-list.json)\n if [ -n \"$run_id\" ]; then\n echo \"Falling back to GitHub Actions logs for run ID: $run_id\"\n gh api \"repos/${{ github.repository }}/actions/runs/${run_id}/logs\" \\\n > \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" 2>&1 || true\n \n if [ -f \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" ] && [ -s \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" ]; then\n unzip -q \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" -d \"/tmp/gh-aw/session-data/logs/${session_number}/\" 2>/dev/null || true\n rm \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\"\n fi\n fi\n }\n fi\n fi\n done\n \n LOG_COUNT=$(find /tmp/gh-aw/session-data/logs/ -type f -name \"*-conversation.txt\" | wc -l)\n echo \"Conversation logs downloaded: $LOG_COUNT session logs\"\n \n FALLBACK_COUNT=$(find /tmp/gh-aw/session-data/logs/ -type d -mindepth 1 | wc -l)\n if [ \"$FALLBACK_COUNT\" -gt 0 ]; then\n echo \"Fallback GitHub Actions logs: $FALLBACK_COUNT sessions\"\n fi\n\n # Store in cache with today's date\n cp /tmp/gh-aw/session-data/sessions-list.json \"$CACHE_DIR/copilot-sessions-${TODAY}.json\"\n cp /tmp/gh-aw/session-data/sessions-schema.json \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\"\n \n # Cache the log files\n mkdir -p \"$CACHE_DIR/session-logs-${TODAY}\"\n cp -r /tmp/gh-aw/session-data/logs/* \"$CACHE_DIR/session-logs-${TODAY}/\" 2>/dev/null || true\n\n echo \"✓ Session data saved to cache: copilot-sessions-${TODAY}.json\"\n echo \"Total sessions found: $(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\"\nfi\n\n# Always ensure data is available at expected locations for backward compatibility\necho \"Session data available at: /tmp/gh-aw/session-data/sessions-list.json\"\necho \"Schema available at: /tmp/gh-aw/session-data/sessions-schema.json\"\necho \"Logs available at: /tmp/gh-aw/session-data/logs/\"\n\n# Set outputs for downstream use\necho \"sessions_count=$(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\" >> \"$GITHUB_OUTPUT\"" + run: "# Create output directories\nmkdir -p /tmp/gh-aw/session-data\nmkdir -p /tmp/gh-aw/session-data/logs\nmkdir -p /tmp/gh-aw/cache-memory\n\n# Get today's date for cache identification\nTODAY=$(date '+%Y-%m-%d')\nCACHE_DIR=\"/tmp/gh-aw/cache-memory\"\n\n# Check if cached data exists from today\nif [ -f \"$CACHE_DIR/copilot-sessions-${TODAY}.json\" ] && [ -s \"$CACHE_DIR/copilot-sessions-${TODAY}.json\" ]; then\n echo \"✓ Found cached session data from ${TODAY}\"\n cp \"$CACHE_DIR/copilot-sessions-${TODAY}.json\" /tmp/gh-aw/session-data/sessions-list.json\n \n # Regenerate schema if missing\n if [ ! -f \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\" ]; then\n /tmp/gh-aw/jqschema.sh < /tmp/gh-aw/session-data/sessions-list.json > \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\"\n fi\n cp \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\" /tmp/gh-aw/session-data/sessions-schema.json\n \n # Restore cached log files if they exist\n if [ -d \"$CACHE_DIR/session-logs-${TODAY}\" ]; then\n echo \"✓ Found cached session logs from ${TODAY}\"\n cp -r \"$CACHE_DIR/session-logs-${TODAY}\"/* /tmp/gh-aw/session-data/logs/ 2>/dev/null || true\n echo \"Restored $(find /tmp/gh-aw/session-data/logs -type f | wc -l) session log files from cache\"\n fi\n \n echo \"Using cached data from ${TODAY}\"\n echo \"Total sessions in cache: $(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\"\nelse\n echo \"⬇ Downloading fresh session data...\"\n \n # Calculate date 30 days ago\n DATE_30_DAYS_AGO=$(date -d '30 days ago' '+%Y-%m-%d' 2>/dev/null || date -v-30d '+%Y-%m-%d')\n\n # Search for workflow runs from copilot/* branches\n # This fetches GitHub Copilot coding agent task runs by searching for workflow runs on copilot/* branches\n echo \"Fetching Copilot coding agent workflow runs from the last 30 days...\"\n \n # Get workflow runs from copilot/* branches\n gh api \"repos/${{ github.repository }}/actions/runs\" \\\n --paginate \\\n --jq \".workflow_runs[] | select(.head_branch | startswith(\\\"copilot/\\\")) | select(.created_at >= \\\"${DATE_30_DAYS_AGO}\\\") | {id, name, head_branch, created_at, updated_at, status, conclusion, html_url}\" \\\n | jq -s '.[0:50]' \\\n > /tmp/gh-aw/session-data/sessions-list.json\n\n # Generate schema for reference\n /tmp/gh-aw/jqschema.sh < /tmp/gh-aw/session-data/sessions-list.json > /tmp/gh-aw/session-data/sessions-schema.json\n\n # Download conversation logs using gh agent-task command (limit to first 50)\n SESSION_COUNT=$(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\n echo \"Downloading conversation logs for $SESSION_COUNT sessions...\"\n \n # Use gh agent-task to fetch session logs with conversation transcripts\n # Extract session numbers from head_branch (format: copilot/issue-123 or copilot/task-456)\n # The number is the issue/task/PR number that the gh agent-task command uses\n jq -r '.[].head_branch' /tmp/gh-aw/session-data/sessions-list.json | while read -r branch; do\n if [ -n \"$branch\" ]; then\n # Extract number from branch name (e.g., copilot/issue-123 -> 123)\n # This is the session identifier used by gh agent-task\n session_number=$(echo \"$branch\" | sed 's/copilot\\///' | sed 's/[^0-9]//g')\n \n if [ -n \"$session_number\" ]; then\n echo \"Downloading conversation log for session #$session_number (branch: $branch)\"\n \n # Use gh agent-task view --log to get conversation transcript\n # This contains the agent's internal monologue, tool calls, and reasoning\n gh agent-task view --repo \"${{ github.repository }}\" \"$session_number\" --log \\\n > \"/tmp/gh-aw/session-data/logs/${session_number}-conversation.txt\" 2>&1 || {\n echo \"Warning: Could not fetch conversation log for session #$session_number\"\n # If gh agent-task fails, fall back to downloading GitHub Actions logs\n # This ensures we have some data even if agent-task command is unavailable\n run_id=$(jq -r \".[] | select(.head_branch == \\\"$branch\\\") | .id\" /tmp/gh-aw/session-data/sessions-list.json)\n if [ -n \"$run_id\" ]; then\n echo \"Falling back to GitHub Actions logs for run ID: $run_id\"\n gh api \"repos/${{ github.repository }}/actions/runs/${run_id}/logs\" \\\n > \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" 2>&1 || true\n \n if [ -f \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" ] && [ -s \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" ]; then\n unzip -q \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\" -d \"/tmp/gh-aw/session-data/logs/${session_number}/\" 2>/dev/null || true\n rm \"/tmp/gh-aw/session-data/logs/${session_number}-actions.zip\"\n fi\n fi\n }\n fi\n fi\n done\n \n LOG_COUNT=$(find /tmp/gh-aw/session-data/logs/ -type f -name \"*-conversation.txt\" | wc -l)\n echo \"Conversation logs downloaded: $LOG_COUNT session logs\"\n \n FALLBACK_COUNT=$(find /tmp/gh-aw/session-data/logs/ -type d -mindepth 1 | wc -l)\n if [ \"$FALLBACK_COUNT\" -gt 0 ]; then\n echo \"Fallback GitHub Actions logs: $FALLBACK_COUNT sessions\"\n fi\n\n # Store in cache with today's date\n cp /tmp/gh-aw/session-data/sessions-list.json \"$CACHE_DIR/copilot-sessions-${TODAY}.json\"\n cp /tmp/gh-aw/session-data/sessions-schema.json \"$CACHE_DIR/copilot-sessions-${TODAY}-schema.json\"\n \n # Cache the log files\n mkdir -p \"$CACHE_DIR/session-logs-${TODAY}\"\n cp -r /tmp/gh-aw/session-data/logs/* \"$CACHE_DIR/session-logs-${TODAY}/\" 2>/dev/null || true\n\n echo \"✓ Session data saved to cache: copilot-sessions-${TODAY}.json\"\n echo \"Total sessions found: $(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\"\nfi\n\n# Always ensure data is available at expected locations for backward compatibility\necho \"Session data available at: /tmp/gh-aw/session-data/sessions-list.json\"\necho \"Schema available at: /tmp/gh-aw/session-data/sessions-schema.json\"\necho \"Logs available at: /tmp/gh-aw/session-data/logs/\"\n\n# Set outputs for downstream use\necho \"sessions_count=$(jq 'length' /tmp/gh-aw/session-data/sessions-list.json)\" >> \"$GITHUB_OUTPUT\"" - name: Setup Python environment run: "# Create working directory for Python scripts\nmkdir -p /tmp/gh-aw/python\nmkdir -p /tmp/gh-aw/python/data\nmkdir -p /tmp/gh-aw/python/charts\nmkdir -p /tmp/gh-aw/python/artifacts\n\necho \"Python environment setup complete\"\necho \"Working directory: /tmp/gh-aw/python\"\necho \"Data directory: /tmp/gh-aw/python/data\"\necho \"Charts directory: /tmp/gh-aw/python/charts\"\necho \"Artifacts directory: /tmp/gh-aw/python/artifacts\"\n" - name: Install Python scientific libraries @@ -1174,7 +1174,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: WORKFLOW_NAME: "Copilot Session Insights" - WORKFLOW_DESCRIPTION: "Analyzes GitHub Copilot agent sessions to provide detailed insights on usage patterns, success rates, and performance metrics" + WORKFLOW_DESCRIPTION: "Analyzes GitHub Copilot coding agent sessions to provide detailed insights on usage patterns, success rates, and performance metrics" HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | diff --git a/.github/workflows/copilot-session-insights.md b/.github/workflows/copilot-session-insights.md index 7b9ef8b41cb..7c3323365d7 100644 --- a/.github/workflows/copilot-session-insights.md +++ b/.github/workflows/copilot-session-insights.md @@ -1,6 +1,6 @@ --- name: Copilot Session Insights -description: Analyzes GitHub Copilot agent sessions to provide detailed insights on usage patterns, success rates, and performance metrics +description: Analyzes GitHub Copilot coding agent sessions to provide detailed insights on usage patterns, success rates, and performance metrics on: schedule: # Daily at 8:00 AM Pacific Time (16:00 UTC) @@ -58,13 +58,13 @@ timeout-minutes: 20 --- -# Copilot Agent Session Analysis +# Copilot coding agent Session Analysis -You are an AI analytics agent specializing in analyzing Copilot agent sessions to extract insights, identify behavioral patterns, and recommend improvements. +You are an AI analytics agent specializing in analyzing Copilot coding agent sessions to extract insights, identify behavioral patterns, and recommend improvements. ## Mission -Analyze approximately 50 Copilot agent sessions to identify: +Analyze approximately 50 Copilot coding agent sessions to identify: - Behavioral patterns and inefficiencies - Success factors and failure signals - Prompt quality indicators @@ -493,7 +493,7 @@ If approaching timeout: A successful analysis includes: -- ✅ Analyzed ~50 Copilot agent sessions +- ✅ Analyzed ~50 Copilot coding agent sessions - ✅ Calculated key metrics (completion rate, duration, quality) - ✅ Identified success factors and failure signals - ✅ Generated actionable recommendations diff --git a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml index c9cdf446c68..d4f0e8e60ce 100644 --- a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml +++ b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml @@ -440,12 +440,12 @@ jobs: "name": "create_issue" }, { - "description": "Create a GitHub Copilot agent session to delegate coding work. Use this when you need another Copilot agent to implement code changes, fix bugs, or complete development tasks. The task becomes a new issue that triggers the Copilot coding agent. For non-coding tasks or manual work items, use create_issue instead. CONSTRAINTS: Maximum 3 agent task(s) can be created.", + "description": "Create a GitHub Copilot coding agent session to delegate coding work. Use this when you need another Copilot coding agent to implement code changes, fix bugs, or complete development tasks. The task becomes a new issue that triggers the Copilot coding agent. For non-coding tasks or manual work items, use create_issue instead. CONSTRAINTS: Maximum 3 agent task(s) can be created.", "inputSchema": { "additionalProperties": false, "properties": { "body": { - "description": "Clear, detailed task description for the Copilot agent. Include specific files to modify, expected behavior, acceptance criteria, and any constraints. The description should be actionable and self-contained.", + "description": "Clear, detailed task description for the Copilot coding agent. Include specific files to modify, expected behavior, acceptance criteria, and any constraints. The description should be actionable and self-contained.", "type": "string" } }, @@ -1184,7 +1184,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} with: - github-token: ${{ secrets.COPILOT_GITHUB_TOKEN || secrets.GH_AW_GITHUB_TOKEN }} + github-token: ${{ secrets.COPILOT_GITHUB_TOKEN }} script: | const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io); diff --git a/.github/workflows/daily-mcp-concurrency-analysis.md b/.github/workflows/daily-mcp-concurrency-analysis.md index 30701f5af68..33efc894362 100644 --- a/.github/workflows/daily-mcp-concurrency-analysis.md +++ b/.github/workflows/daily-mcp-concurrency-analysis.md @@ -393,7 +393,7 @@ describe('${TOOL_NAME} concurrency safety', () => { #### Optionally Create Agent Session -For CRITICAL or HIGH severity issues, consider creating a Copilot agent session: +For CRITICAL or HIGH severity issues, consider creating a Copilot coding agent session: ```markdown Fix the concurrency safety issue in \`${TOOL_NAME}\` tool. diff --git a/.github/workflows/daily-safe-outputs-conformance.md b/.github/workflows/daily-safe-outputs-conformance.md index 88a760de9de..a7e079a352d 100644 --- a/.github/workflows/daily-safe-outputs-conformance.md +++ b/.github/workflows/daily-safe-outputs-conformance.md @@ -47,7 +47,7 @@ Your mission is to: - Clear description of the conformance violation - Severity level and check ID - Specific files or code locations affected - - Actionable remediation steps suitable for Copilot agent assignment + - Actionable remediation steps suitable for Copilot coding agent assignment 4. Close older issues from previous runs (auto-handled by expires: 1d and close-older-issues: true) ## Phase 1: Run Conformance Checks @@ -127,7 +127,7 @@ Example: `SEC-001: Agent job in workflow X has write permissions` ## Remediation Steps -This task can be assigned to a Copilot agent with the following steps: +This task can be assigned to a Copilot coding agent with the following steps: 1. [Specific action 1] 2. [Specific action 2] diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml index d35def1b55d..f8dc8b5895d 100644 --- a/.github/workflows/issue-monster.lock.yml +++ b/.github/workflows/issue-monster.lock.yml @@ -21,13 +21,13 @@ # # For more information: https://github.github.com/gh-aw/introduction/overview/ # -# The Cookie Monster of issues - assigns issues to Copilot agents one at a time +# The Cookie Monster of issues - assigns issues to Copilot coding agent one at a time # # Resolved workflow manifest: # Imports: # - shared/mood.md # -# frontmatter-hash: 499084bba53b33d3d6741037f0e2e17178fb144120241576df249aaa6f511842 +# frontmatter-hash: dc34e052a20e5b53d141cd9277e9497b52ffebc098737e1b728e4ed3bf5a71bc name: "Issue Monster" "on": @@ -429,14 +429,14 @@ jobs: "type": "string" }, "issue_number": { - "description": "Issue number to assign the Copilot agent to. This is the numeric ID from the GitHub URL (e.g., 234 in github.com/owner/repo/issues/234). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from an issue created earlier in the same workflow run. The issue should contain clear, actionable requirements. Either issue_number or pull_number must be provided, but not both.", + "description": "Issue number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 234 in github.com/owner/repo/issues/234). Can also be a temporary_id (e.g., 'aw_abc123', 'aw_Test123') from an issue created earlier in the same workflow run. The issue should contain clear, actionable requirements. Either issue_number or pull_number must be provided, but not both.", "type": [ "number", "string" ] }, "pull_number": { - "description": "Pull request number to assign the Copilot agent to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/pull/456). Either issue_number or pull_number must be provided, but not both.", + "description": "Pull request number to assign the Copilot coding agent to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/pull/456). Either issue_number or pull_number must be provided, but not both.", "type": [ "number", "string" @@ -1000,7 +1000,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: WORKFLOW_NAME: "Issue Monster" - WORKFLOW_DESCRIPTION: "The Cookie Monster of issues - assigns issues to Copilot agents one at a time" + WORKFLOW_DESCRIPTION: "The Cookie Monster of issues - assigns issues to Copilot coding agent one at a time" HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | @@ -1444,7 +1444,7 @@ jobs: return false; } - // Exclude issues with open PRs from Copilot agent + // Exclude issues with open PRs from Copilot coding agent const openCopilotPRs = issue.linkedPRs?.filter(pr => pr.state === 'OPEN' && (pr.author === 'copilot-swe-agent' || pr.author?.includes('copilot')) diff --git a/.github/workflows/issue-monster.md b/.github/workflows/issue-monster.md index df26ae4ca26..ec4e7a76645 100644 --- a/.github/workflows/issue-monster.md +++ b/.github/workflows/issue-monster.md @@ -1,6 +1,6 @@ --- name: Issue Monster -description: The Cookie Monster of issues - assigns issues to Copilot agents one at a time +description: The Cookie Monster of issues - assigns issues to Copilot coding agent one at a time on: workflow_dispatch: schedule: every 30m @@ -273,7 +273,7 @@ jobs: return false; } - // Exclude issues with open PRs from Copilot agent + // Exclude issues with open PRs from Copilot coding agent const openCopilotPRs = issue.linkedPRs?.filter(pr => pr.state === 'OPEN' && (pr.author === 'copilot-swe-agent' || pr.author?.includes('copilot')) @@ -383,11 +383,11 @@ imports: # Issue Monster 🍪 -You are the **Issue Monster** - the Cookie Monster of issues! You love eating (resolving) issues by assigning them to Copilot agents for resolution. +You are the **Issue Monster** - the Cookie Monster of issues! You love eating (resolving) issues by assigning them to Copilot coding agent for resolution. ## Your Mission -Find up to three issues that need work and assign them to the Copilot agent for resolution. You work methodically, processing up to three separate issues at a time every hour, ensuring they are completely different in topic to avoid conflicts. +Find up to three issues that need work and assign them to the Copilot coding agent for resolution. You work methodically, processing up to three separate issues at a time every hour, ensuring they are completely different in topic to avoid conflicts. ## Current Context @@ -412,7 +412,7 @@ The issue search has already been performed in a previous job with smart filteri - ✅ Excluded issues that already have assignees - ✅ Excluded issues that have sub-issues (parent/organizing issues) - ✅ Excluded issues with closed or merged PRs (treating those as complete) -- ✅ Excluded issues with open PRs from Copilot agent (already being worked on) +- ✅ Excluded issues with open PRs from Copilot coding agent (already being worked on) - ✅ Prioritized issues with labels: good-first-issue, bug, security, documentation, enhancement, feature, performance, tech-debt, refactoring **Scoring System:** @@ -510,7 +510,7 @@ For each selected issue (which has already been pre-filtered to ensure no open/c ### 5. Assign Issues to Copilot Agent -For each selected issue, use the `assign_to_agent` tool from the `safeoutputs` MCP server to assign the Copilot agent: +For each selected issue, use the `assign_to_agent` tool from the `safeoutputs` MCP server to assign the Copilot coding agent: ``` safeoutputs/assign_to_agent(issue_number=, agent="copilot") @@ -518,7 +518,7 @@ safeoutputs/assign_to_agent(issue_number=, agent="copilot") Do not use GitHub tools for this assignment. The `assign_to_agent` tool will handle the actual assignment. -The Copilot agent will: +The Copilot coding agent will: 1. Analyze the issue and related context 2. Generate the necessary code changes 3. Create a pull request with the fix @@ -529,7 +529,7 @@ The Copilot agent will: For each issue you assign, use the `add_comment` tool from the `safeoutputs` MCP server to add a comment: ``` -safeoutputs/add_comment(item_number=, body="🍪 **Issue Monster has assigned this to Copilot!**\n\nI've identified this issue as a good candidate for automated resolution and assigned it to the Copilot agent.\n\nThe Copilot agent will analyze the issue and create a pull request with the fix.\n\nOm nom nom! 🍪") +safeoutputs/add_comment(item_number=, body="🍪 **Issue Monster has assigned this to Copilot!**\n\nI've identified this issue as a good candidate for automated resolution and assigned it to the Copilot coding agent.\n\nThe Copilot coding agent will analyze the issue and create a pull request with the fix.\n\nOm nom nom! 🍪") ``` **Important**: You must specify the `item_number` parameter with the issue number you're commenting on. This workflow runs on a schedule without a triggering issue, so the target must be explicitly specified. @@ -555,13 +555,13 @@ A successful run means: 5. The search already excluded issues that already have assignees 6. The search already excluded issues that have sub-issues (parent/organizing issues are not tasks) 7. The search already excluded issues with closed or merged PRs (treated as complete) -8. The search already excluded issues with open PRs from Copilot agent (already being worked on) +8. The search already excluded issues with open PRs from Copilot coding agent (already being worked on) 9. Issues are sorted by priority score (good-first-issue, bug, security, etc. get higher scores) 10. For "task" or "plan" issues: You checked for parent issues and sibling sub-issue PRs if necessary 11. You selected up to three appropriate issues from the top of the priority list that are completely separate in topic 12. You read and understood each issue 13. You verified that the selected issues don't have overlapping concerns or file changes -14. You assigned each issue to the Copilot agent using `assign_to_agent` +14. You assigned each issue to the Copilot coding agent using `assign_to_agent` 15. You commented on each issue being assigned ## Error Handling diff --git a/.github/workflows/plan.md b/.github/workflows/plan.md index 967e4ba91e3..bbb934baf9d 100644 --- a/.github/workflows/plan.md +++ b/.github/workflows/plan.md @@ -31,7 +31,7 @@ imports: # Planning Assistant -You are an expert planning assistant for GitHub Copilot agents. Your task is to analyze an issue or discussion and break it down into a sequence of actionable work items that can be assigned to GitHub Copilot agents. +You are an expert planning assistant for GitHub Copilot coding agent. Your task is to analyze an issue or discussion and break it down into a sequence of actionable work items that can be assigned to GitHub Copilot coding agent. ## Current Context @@ -46,7 +46,7 @@ ${{ steps.sanitized.outputs.text }} ## Your Mission -Analyze the issue or discussion along with the comment content (which may contain additional guidance from the user), then create actionable sub-issues (at most 5) that can be assigned to GitHub Copilot agents. +Analyze the issue or discussion along with the comment content (which may contain additional guidance from the user), then create actionable sub-issues (at most 5) that can be assigned to GitHub Copilot coding agent. **Important**: With issue grouping enabled, all issues you create will be automatically grouped under a parent tracking issue. You don't need to create a parent issue manually or use temporary IDs - just create the sub-issues directly. diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index bbf8bb6eedb..6e52d723791 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -465,12 +465,12 @@ jobs: "name": "create_issue" }, { - "description": "Create a GitHub Copilot agent session to delegate coding work. Use this when you need another Copilot agent to implement code changes, fix bugs, or complete development tasks. The task becomes a new issue that triggers the Copilot coding agent. For non-coding tasks or manual work items, use create_issue instead. CONSTRAINTS: Maximum 1 agent task(s) can be created. Base branch for tasks: \"main\".", + "description": "Create a GitHub Copilot coding agent session to delegate coding work. Use this when you need another Copilot coding agent to implement code changes, fix bugs, or complete development tasks. The task becomes a new issue that triggers the Copilot coding agent. For non-coding tasks or manual work items, use create_issue instead. CONSTRAINTS: Maximum 1 agent task(s) can be created. Base branch for tasks: \"main\".", "inputSchema": { "additionalProperties": false, "properties": { "body": { - "description": "Clear, detailed task description for the Copilot agent. Include specific files to modify, expected behavior, acceptance criteria, and any constraints. The description should be actionable and self-contained.", + "description": "Clear, detailed task description for the Copilot coding agent. Include specific files to modify, expected behavior, acceptance criteria, and any constraints. The description should be actionable and self-contained.", "type": "string" } }, @@ -1821,7 +1821,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} GH_AW_SAFE_OUTPUTS_STAGED: "true" with: - github-token: ${{ secrets.COPILOT_GITHUB_TOKEN || secrets.GH_AW_GITHUB_TOKEN }} + github-token: ${{ secrets.COPILOT_GITHUB_TOKEN }} script: | const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io); diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index f39649bf07c..924f8427e6c 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -21,7 +21,7 @@ # # For more information: https://github.github.com/gh-aw/introduction/overview/ # -# Analyzes and clusters GitHub Copilot agent prompts to identify patterns and usage trends +# Analyzes and clusters GitHub Copilot coding agent prompts to identify patterns and usage trends # # Resolved workflow manifest: # Imports: @@ -31,7 +31,7 @@ # - shared/reporting.md # - shared/trending-charts-simple.md # -# frontmatter-hash: 55aaa5cabc63a05ec6ecd37b694afaec14d2ff60837e05c4fbc60f57adeb888d +# frontmatter-hash: 5916161eaa3bed8bf2747c838309559e94337286bb6b11175d447c18e0f869a6 name: "Copilot Agent Prompt Clustering Analysis" "on": @@ -1156,7 +1156,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: WORKFLOW_NAME: "Copilot Agent Prompt Clustering Analysis" - WORKFLOW_DESCRIPTION: "Analyzes and clusters GitHub Copilot agent prompts to identify patterns and usage trends" + WORKFLOW_DESCRIPTION: "Analyzes and clusters GitHub Copilot coding agent prompts to identify patterns and usage trends" HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | diff --git a/.github/workflows/prompt-clustering-analysis.md b/.github/workflows/prompt-clustering-analysis.md index 56ce0691f3d..3922a30d09b 100644 --- a/.github/workflows/prompt-clustering-analysis.md +++ b/.github/workflows/prompt-clustering-analysis.md @@ -1,6 +1,6 @@ --- name: Copilot Agent Prompt Clustering Analysis -description: Analyzes and clusters GitHub Copilot agent prompts to identify patterns and usage trends +description: Analyzes and clusters GitHub Copilot coding agent prompts to identify patterns and usage trends on: schedule: daily workflow_dispatch: diff --git a/.github/workflows/repository-quality-improver.md b/.github/workflows/repository-quality-improver.md index b0ec32e446b..2eb01a4a7fd 100644 --- a/.github/workflows/repository-quality-improver.md +++ b/.github/workflows/repository-quality-improver.md @@ -341,11 +341,11 @@ Create a comprehensive report using the **reporting MCP** with the following str ## 🤖 Tasks for Copilot Agent -**NOTE TO PLANNER AGENT**: The following tasks are designed for GitHub Copilot agent execution. Please split these into individual work items for Claude to process. +**NOTE TO PLANNER AGENT**: The following tasks are designed for GitHub Copilot coding agent execution. Please split these into individual work items for Claude to process. ### Improvement Tasks -The following code regions and tasks should be processed by the Copilot agent. Each section is marked for easy identification by the planner agent. +The following code regions and tasks should be processed by the Copilot coding agent. Each section is marked for easy identification by the planner agent. #### Task 1: [Short Description] @@ -364,7 +364,7 @@ The following code regions and tasks should be processed by the Copilot agent. E **Code Region:** `[file path or pattern]` ```markdown -[Copilot agent prompt for this task] +[Copilot coding agent prompt for this task] ``` --- @@ -385,7 +385,7 @@ The following code regions and tasks should be processed by the Copilot agent. E **Code Region:** `[file path or pattern]` ```markdown -[Copilot agent prompt for this task] +[Copilot coding agent prompt for this task] ``` --- @@ -438,7 +438,7 @@ Track these metrics to measure improvement in the **[FOCUS AREA]**: ## Next Steps 1. Review and prioritize the tasks above -2. Assign tasks to Copilot agent via planner agent +2. Assign tasks to Copilot coding agent via planner agent 3. Track progress on improvement items 4. Re-evaluate this focus area in [timeframe] @@ -450,7 +450,7 @@ Track these metrics to measure improvement in the **[FOCUS AREA]**: ### Important Report Guidelines -1. **Copilot Agent Section**: Always include a clearly marked section for Copilot agent tasks +1. **Copilot Agent Section**: Always include a clearly marked section for Copilot coding agent tasks 2. **Planner Note**: Include a note for the planner agent to split tasks 3. **Code Regions**: Mark specific files or patterns where changes are needed 4. **Task Format**: Each task should be self-contained with clear acceptance criteria @@ -496,7 +496,7 @@ A successful quality improvement run: - ✅ Conducts thorough analysis of the selected area (using custom analysis for custom areas) - ✅ Uses Serena MCP only when static analysis is needed - ✅ Generates exactly one discussion with the report -- ✅ Includes 3-5 actionable tasks for Copilot agent +- ✅ Includes 3-5 actionable tasks for Copilot coding agent - ✅ Clearly marks code regions for planner agent to split - ✅ Updates cache memory with run history including custom area tracking - ✅ Maintains high diversity rate (aim for 60%+ custom or varied strategies) @@ -549,7 +549,7 @@ When creating custom focus areas specific to gh-aw: Your output MUST: 1. Create exactly one discussion with the quality improvement report -2. Include a clearly marked section for Copilot agent tasks +2. Include a clearly marked section for Copilot coding agent tasks 3. Provide 3-5 actionable tasks with code region markers 4. Note for planner agent to split tasks for Claude 5. Update cache memory with run history (including custom area tracking) @@ -557,4 +557,4 @@ Your output MUST: 7. Use the reporting MCP for structured content 8. **For custom focus areas**: Clearly explain the rationale and custom analysis performed -Begin your quality improvement analysis now. Select a focus area (prioritizing custom, repository-specific areas), conduct appropriate analysis, generate actionable tasks for the Copilot agent, and create the discussion report. +Begin your quality improvement analysis now. Select a focus area (prioritizing custom, repository-specific areas), conduct appropriate analysis, generate actionable tasks for the Copilot coding agent, and create the discussion report. diff --git a/.github/workflows/shared/copilot-pr-data-fetch.md b/.github/workflows/shared/copilot-pr-data-fetch.md index 0fdab45d67a..340e023c998 100644 --- a/.github/workflows/shared/copilot-pr-data-fetch.md +++ b/.github/workflows/shared/copilot-pr-data-fetch.md @@ -74,7 +74,7 @@ steps: