Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 3, 2026

The init command was embedding all instruction files from .github/aw/ and .github/agents/ into the binary via go:embed, then syncing them during build. This created a dual source of truth and unnecessary binary bloat.

Changes

Agent file (downloaded on demand with URL patching)

  • The .github/agents/agentic-workflows.agent.md file is no longer embedded in the binary
  • Added downloadAgentFileFromGitHub() function that downloads the agent file from GitHub on demand
  • For release builds (version starts with v), uses the release tag to get version-matched file
  • For dev builds, uses the main branch
  • Downloads from https://raw.githubusercontent.com/github/gh-aw/{ref}/.github/agents/agentic-workflows.agent.md
  • Includes 30-second timeout for reliability
  • Automatically patches URLs in downloaded content via patchAgentFileURLs() function:
    • Converts local paths (.github/aw/file.md) to full GitHub URLs
    • Patches /blob/main/ to /blob/{version}/ for release builds
    • Ensures all documentation links match the installed version

Agent file references

  • Updated .github/agents/agentic-workflows.agent.md to reference prompts via GitHub URLs:
    **Prompt file**: https://github.com/github/gh-aw/blob/main/.github/aw/create-agentic-workflow.md
    instead of:
    **Prompt file**: `.github/aw/create-agentic-workflow.md`

Removed all embedded templates

  • Deleted all go:embed directives from pkg/cli/commands.go (no markdown files are embedded)
  • Removed pkg/cli/templates/ directory completely (8 markdown files, ~5000 lines)
  • Removed sync-templates target from Makefile
  • Updated build and recompile targets to not depend on template syncing

Simplified prompt file handling

  • Modified copilot-agents.go functions for prompt files to check file existence only (no creation from templates)
  • Removed ensureFileMatchesTemplate() and ensureAgentFromTemplate() - unused after template removal
  • Updated tests to reflect that init validates prompt files rather than creating them

Added cleanup for existing installations

  • Added deleteOldTemplateFiles() function to remove all old template files from pkg/cli/templates/ directory (8 files)
  • Integrated cleanup into gh aw fix --write command
  • Automatically removes the empty templates/ directory after cleanup
  • Added comprehensive tests for the cleanup logic
  • Updated help text to document the cleanup behavior

Result

  • No embedding: Binary no longer contains any markdown files
  • Agent file: Downloaded from GitHub on each init, using version-matched tag for releases
  • URL patching: All URLs in the agent file are automatically patched to match the installed version:
    • Dev builds: URLs point to /blob/main/
    • Release v1.2.3: URLs point to /blob/v1.2.3/
  • Prompt files: .github/aw/*.md files are NOT embedded, serve as source of truth in gh-aw repo, and are referenced via GitHub URLs
  • Cleanup: gh aw fix --write removes all old template files and the templates directory

Users with existing installations can run gh aw fix --write to automatically clean up all old template files that are no longer needed.

Example URL patching:

  • Input (from GitHub): .github/aw/create-agentic-workflow.md
  • Output for v1.2.3: https://github.com/github/gh-aw/blob/v1.2.3/.github/aw/create-agentic-workflow.md
  • Output for dev build: https://github.com/github/gh-aw/blob/main/.github/aw/create-agentic-workflow.md
Original prompt

We are going to reconfigure and refactor the files created by the init command.

Stop bundling the markdown files under the .github/aw folder. Instead, update agentic-workflows.agent.yaml so that the agent references the GitHub URLs for those files.

Also remove the markdown files from the compiler project, remove them from the Go compiler, and remove the script that copies the files from gh-aw to the Go compiler. The source of truth should be the version under .github/aw.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI and others added 2 commits February 4, 2026 00:09
…rkdown files

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor

@pelikhan pelikhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add codemod to remove the old markdown files from existing installations. @copilot

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Reconfigure and refactor markdown file handling Stop bundling markdown files, reference via GitHub URLs Feb 4, 2026
Copilot AI requested a review from pelikhan February 4, 2026 00:23
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

Add codemod to remove the old markdown files from existing installations. @copilot

Added cleanup logic in commit 98c479d. The gh aw fix --write command now removes old template files from pkg/cli/templates/ and deletes the empty directory if all files are removed.

Cleanup includes:

  • deleteOldTemplateFiles() function removes 8 old markdown files
  • Integrated into fix command (runs with --write flag)
  • Added comprehensive tests for the cleanup logic
  • Updated help text to document the new cleanup behavior

@pelikhan
Copy link
Contributor

pelikhan commented Feb 4, 2026

@copilot The .github/agents/agentic-workflows.agent.md still needs to be written by the init command so it needs to be embedded by the go compiler.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

🔍 PR Triage Results

Category: refactor | Risk: high | Priority: 68/100

Scores Breakdown

  • Impact: 38/50 - Major refactoring removing embedded templates from binary; 379 additions, 5215 deletions across 23 files; simplifies build process; changes init command behavior; removes sync-templates target from Makefile
  • Urgency: 18/30 - Created 0.6 hours ago; draft status; 6 commits; 1 comment; assigned to pelikhan; significant architectural change but not urgent
  • Quality: 12/20 - CI unstable; draft status; comprehensive description with clear before/after examples; includes cleanup functionality for existing installations; massive code deletion (5215 lines) indicates good cleanup

📋 Recommended Action: fast_track

Significant architectural improvement that simplifies the codebase by removing 5000+ lines of embedded template code. The PR makes .github/aw/ the single source of truth and eliminates dual maintenance. While in draft, the scope and impact warrant fast-track review once ready. This is the kind of refactoring that reduces technical debt and improves maintainability.


Triaged by PR Triage Agent on 2026-02-04T00:35:56Z

AI generated by PR Triage Agent

@pelikhan
Copy link
Contributor

pelikhan commented Feb 4, 2026

@copilot remove the agent.md file embedded from the go compiler and installl download it on demand from GitHub. If the cli is a release build, use the release tag to get the version matching the current binary.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

@copilot The .github/agents/agentic-workflows.agent.md still needs to be written by the init command so it needs to be embedded by the go compiler.

Fixed in commit 24b002a. The agentic-workflows.agent.md file is now:

  • Re-embedded in the binary via go:embed templates/agentic-workflows.agent.md
  • Synced from .github/agents/ to pkg/cli/templates/ during build
  • Written by the init command to create the file in user repositories
  • Excluded from cleanup (only the 7 prompt files in .github/aw/ are removed by fix --write)

The agent file is now properly embedded while prompt files remain unbundled.

Copilot AI changed the title Stop bundling markdown files, reference via GitHub URLs Stop bundling prompt files, embed agent file, reference prompts via GitHub URLs Feb 4, 2026
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

@copilot remove the agent.md file embedded from the go compiler and installl download it on demand from GitHub. If the cli is a release build, use the release tag to get the version matching the curre...

Implemented in commit 6d583a8. The agent file is now downloaded on demand from GitHub:

  • Removed go:embed directive for agent file
  • Added downloadAgentFileFromGitHub() function that uses release tag for releases, main branch for dev builds
  • Downloads from https://raw.githubusercontent.com/github/gh-aw/{version}/.github/agents/agentic-workflows.agent.md
  • Updated cleanup to remove all 8 template files including agent file
  • Removed sync-agent-template target and pkg/cli/templates/ directory completely

The binary no longer embeds any markdown files.

Copilot AI changed the title Stop bundling prompt files, embed agent file, reference prompts via GitHub URLs Download agent file from GitHub on demand, reference prompts via URLs Feb 4, 2026
@pelikhan
Copy link
Contributor

pelikhan commented Feb 4, 2026

@copilot the downloaded agent file should patch the GitHub/gh-aw URLs to match the release tag

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

@copilot the downloaded agent file should patch the GitHub/gh-aw URLs to match the release tag

Implemented in commit a040410. Added patchAgentFileURLs() function that:

  • Converts local paths (.github/aw/file.md) to full GitHub URLs
  • Patches /blob/main/ to /blob/{version}/ for release builds
  • Uses appropriate ref (main for dev, release tag for releases)
  • Handles both local paths and existing GitHub URLs

Example: For release v1.2.3, .github/aw/create-agentic-workflow.md becomes https://github.com/github/gh-aw/blob/v1.2.3/.github/aw/create-agentic-workflow.md

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Download agent file from GitHub on demand, reference prompts via URLs Download agent file from GitHub on demand with version-aware URL patching Feb 4, 2026
@pelikhan pelikhan marked this pull request as ready for review February 4, 2026 03:39
Copilot AI review requested due to automatic review settings February 4, 2026 03:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the template file system to eliminate binary bloat by downloading the agent file from GitHub on demand rather than embedding markdown files in the binary. The agent file is version-aware, downloading from the appropriate release tag or main branch, and URLs within the file are automatically patched to match the installed version.

Changes:

  • Removed all go:embed directives and deleted 8 template markdown files (~5000 lines) from pkg/cli/templates/
  • Added downloadAgentFileFromGitHub() to fetch the agent file from GitHub with 30-second timeout
  • Implemented patchAgentFileURLs() to convert local paths to versioned GitHub URLs
  • Modified ensureAgenticWorkflowsDispatcher() to download and write agent file instead of using embedded template
  • Changed all other ensure* functions to check file existence only (no creation from templates)
  • Added deleteOldTemplateFiles() integrated into gh aw fix --write for cleanup
  • Updated .github/agents/agentic-workflows.agent.md to reference prompts via GitHub URLs instead of local paths
  • Removed sync-templates target from Makefile

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/cli/commands.go Added download and URL patching functions with version detection
pkg/cli/copilot-agents.go Refactored ensure functions to download agent file and check file existence only
pkg/cli/fix_command.go Integrated template cleanup into fix command
pkg/cli/*_test.go Updated tests to reflect new behavior (check existence vs create from template)
pkg/cli/templates/*.md Deleted all embedded template files (8 files)
.github/agents/agentic-workflows.agent.md Updated to use GitHub URLs for prompt references
Makefile Removed sync-templates target and dependencies
Comments suppressed due to low confidence (1)

pkg/cli/commands.go:115

  • The URL patching at line 114 will replace ALL occurrences of /blob/main/ in the content, not just those in GitHub URLs. This could potentially modify unintended content if the string /blob/main/ appears in:
  • Code examples showing how to construct GitHub URLs
  • Explanatory text or documentation
  • Markdown code blocks
  • Comments in the agent file

For example, if the agent file contains:

Example: `https://github.com/other-org/other-repo/blob/main/file.md` should not be changed

This would incorrectly become:

Example: `https://github.com/other-org/other-repo/blob/v1.2.3/file.md`

Consider making the replacement more targeted by:

  1. Only replacing within github.com/github/gh-aw/ URLs
  2. Using a regex pattern that matches the full URL structure
  3. Or documenting that the agent file should avoid this pattern in non-reference contexts

Example safer implementation:

if ref != "main" {
    // Only replace in gh-aw repository URLs
    content = strings.ReplaceAll(content, 
        "https://github.com/github/gh-aw/blob/main/", 
        fmt.Sprintf("https://github.com/github/gh-aw/blob/%s/", ref))
}
	if ref != "main" {
		content = strings.ReplaceAll(content, "/blob/main/", fmt.Sprintf("/blob/%s/", ref))
	}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to 103
func downloadAgentFileFromGitHub(verbose bool) (string, error) {
commandsLog.Print("Downloading agentic-workflows.agent.md from GitHub")

// Determine the ref to use (tag for releases, main for dev builds)
ref := "main"
currentVersion := GetVersion()

// If version looks like a release tag (starts with v and contains dots), use it
isRelease := strings.HasPrefix(currentVersion, "v") && strings.Contains(currentVersion, ".")
if isRelease {
ref = currentVersion
commandsLog.Printf("Using release tag: %s", ref)
if verbose {
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Using release version: %s", ref)))
}
} else {
commandsLog.Print("Using main branch for dev build")
if verbose {
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Using main branch (dev build)"))
}
}

//go:embed templates/update-agentic-workflow.md
var updateWorkflowPromptTemplate string
// Construct the raw GitHub URL
url := fmt.Sprintf("https://raw.githubusercontent.com/github/gh-aw/%s/.github/agents/agentic-workflows.agent.md", ref)
commandsLog.Printf("Downloading from URL: %s", url)

//go:embed templates/create-shared-agentic-workflow.md
var createSharedAgenticWorkflowPromptTemplate string
// Create HTTP client with timeout
client := &http.Client{
Timeout: 30 * time.Second,
}

//go:embed templates/debug-agentic-workflow.md
var debugWorkflowPromptTemplate string
// Download the file
resp, err := client.Get(url)
if err != nil {
return "", fmt.Errorf("failed to download agent file: %w", err)
}
defer resp.Body.Close()

//go:embed templates/upgrade-agentic-workflows.md
var upgradeAgenticWorkflowsPromptTemplate string
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to download agent file: HTTP %d", resp.StatusCode)
}

//go:embed templates/serena-tool.md
var serenaToolTemplate string
// Read the content
content, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read agent file content: %w", err)
}

// SetVersionInfo sets the version information for the CLI and workflow package
func SetVersionInfo(v string) {
version = v
workflow.SetDefaultVersion(v) // Keep workflow package in sync
contentStr := string(content)

// Patch URLs to match the current version/ref
patchedContent := patchAgentFileURLs(contentStr, ref)
if patchedContent != contentStr && verbose {
fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Patched URLs to use ref: %s", ref)))
}

commandsLog.Printf("Successfully downloaded agent file (%d bytes)", len(patchedContent))
return patchedContent, nil
}
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The downloadAgentFileFromGitHub() function has no test coverage. While integration testing network calls can be complex, consider adding unit tests for:

  1. Error handling paths: Test that errors are properly formatted and returned
  2. URL construction logic: Test that the URL is correctly constructed for different version formats
  3. HTTP response handling: Mock HTTP responses to test status code handling (404, 500, etc.)
  4. Content patching: Test the integration between download and URL patching

Example test structure:

func TestDownloadAgentFileFromGitHub(t *testing.T) {
    // Use httptest to mock GitHub responses
    tests := []struct {
        name          string
        version       string
        mockResponse  string
        mockStatus    int
        expectedError bool
        expectedRef   string
    }{
        {
            name: "successful download for release version",
            version: "v1.2.3",
            mockResponse: "# Agent content with `.github/aw/file.md`",
            mockStatus: 200,
            expectedError: false,
            expectedRef: "v1.2.3",
        },
        // ... more test cases
    }
}

This would improve confidence in the download logic without requiring actual network calls during testing.

Copilot uses AI. Check for mistakes.
Comment on lines +106 to 118
func patchAgentFileURLs(content, ref string) string {
// Pattern 1: Convert local paths to GitHub URLs
// `.github/aw/file.md` -> `https://github.com/github/gh-aw/blob/{ref}/.github/aw/file.md`
content = strings.ReplaceAll(content, "`.github/aw/", fmt.Sprintf("`https://github.com/github/gh-aw/blob/%s/.github/aw/", ref))

// Pattern 2: Update existing GitHub URLs to use the correct ref
// https://github.com/github/gh-aw/blob/main/ -> https://github.com/github/gh-aw/blob/{ref}/
if ref != "main" {
content = strings.ReplaceAll(content, "/blob/main/", fmt.Sprintf("/blob/%s/", ref))
}

return content
}
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL patching logic in patchAgentFileURLs() uses simple strings.ReplaceAll() which could potentially cause unintended replacements in edge cases.

Consider this scenario: if the agent file contains explanatory text like "Files stored at .github/aw/ are treated as..." or code examples showing how to write paths like ".github/aw/file.md", ALL occurrences will be patched, not just those in actual reference links.

While this may not be a critical issue in practice (the agent file likely only has reference links), the implementation could be more precise by:

  1. Using a more specific pattern that only matches actual markdown links
  2. Or documenting that the agent file should avoid using this exact pattern in non-reference contexts

However, given the scope of the PR and the controlled nature of the agent file content, this is a minor concern that could be addressed in a follow-up if issues arise.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +124
// Download the agent file from GitHub
agentContent, err := downloadAgentFileFromGitHub(verbose)
if err != nil {
copilotAgentsLog.Printf("Failed to download agent file from GitHub: %v", err)
return fmt.Errorf("failed to download agent file from GitHub: %w", err)
}
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ensureAgenticWorkflowsDispatcher() function now downloads the agent file from GitHub on demand, which introduces a dependency on network connectivity. If the download fails (no internet, GitHub outage, firewall blocking raw.githubusercontent.com), the function returns an error that will propagate up and fail operations like gh aw init and gh aw fix.

This is a significant change in behavior from the previous implementation where files were embedded in the binary and always available offline. Consider:

  1. Fallback handling: When download fails, log a warning but continue gracefully rather than failing the entire operation
  2. Caching: Cache the downloaded file locally and use it as fallback when network is unavailable
  3. Clear error messages: If the download must fail, provide actionable guidance (e.g., "Failed to download agent file. Check internet connectivity or try again later.")

Example improvement:

agentContent, err := downloadAgentFileFromGitHub(verbose)
if err != nil {
    copilotAgentsLog.Printf("Failed to download agent file from GitHub: %v", err)
    // Option 1: Try to use existing file if available
    if existingContent != "" {
        copilotAgentsLog.Print("Using existing agent file")
        return nil // Continue with existing file
    }
    // Option 2: Make it non-fatal with warning
    fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not download agent file: %v. Skipping.", err)))
    return nil
}

This affects user experience in offline scenarios, corporate networks, and during GitHub outages.

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +53
// If version looks like a release tag (starts with v and contains dots), use it
isRelease := strings.HasPrefix(currentVersion, "v") && strings.Contains(currentVersion, ".")
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version detection logic assumes that release versions always start with v and contain dots (e.g., v1.2.3). However, this could fail for valid version formats such as:

  • v1 (single number version)
  • v1.2.3-rc1 (pre-release with suffix)
  • 1.2.3 (without v prefix)

The current logic would incorrectly treat v1 as a dev build (missing dot) and use main branch instead of the v1 tag.

Consider using a more robust version detection approach:

  1. Check if version starts with v followed by at least one digit
  2. Or use semantic version parsing libraries
  3. Or document the exact version format requirements

Example improvement:

import "regexp"
// Match semantic version pattern: v1, v1.2, v1.2.3, v1.2.3-beta, etc.
isRelease := regexp.MustCompile(`^v\d`).MatchString(currentVersion)

This is a minor edge case that may not affect most users, but it could cause confusion if uncommon versioning schemes are used.

Copilot uses AI. Check for mistakes.
@pelikhan
Copy link
Contributor

pelikhan commented Feb 4, 2026

Add @copilot, merge main, and recompile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants