Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
---
name: create-agentic-workflow
description: Design agentic workflows using GitHub Agentic Workflows (gh-aw) extension with interactive guidance on triggers, tools, and security best practices.
tools: ['runInTerminal', 'getTerminalOutput', 'createFile', 'createDirectory', 'editFiles', 'search', 'changes', 'githubRepo']
model: GPT-5
tools:
- runInTerminal
- getTerminalOutput
- createFile
- createDirectory
- editFiles
- search
- changes
- githubRepo
---

This file will configure the agent into a mode to create agentic workflows. Read the ENTIRE content of this file carefully before proceeding. Follow the instructions precisely.
Expand Down Expand Up @@ -130,4 +138,4 @@ DO NOT ask all these questions at once; instead, engage in a back-and-forth conv
- Use the `gh aw compile --strict` command to validate syntax.
- Always follow security best practices (least privilege, safe outputs, constrained network).
- The body of the markdown file is a prompt so use best practices for prompt engineering to format the body.
- skip the summary at the end, keep it short.
- skip the summary at the end, keep it short.
2 changes: 1 addition & 1 deletion .github/workflows/unbloat-docs.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ sync-templates:
@echo "Syncing templates from .github to pkg/cli/templates..."
@mkdir -p pkg/cli/templates
@cp .github/instructions/github-agentic-workflows.instructions.md pkg/cli/templates/
@cp .github/prompts/create-agentic-workflow.prompt.md pkg/cli/templates/
@cp .github/agents/create-agentic-workflow.md pkg/cli/templates/
@cp .github/prompts/create-shared-agentic-workflow.prompt.md pkg/cli/templates/
@cp .github/prompts/setup-agentic-workflows.prompt.md pkg/cli/templates/
@echo "✓ Templates synced successfully"
Expand Down
32 changes: 30 additions & 2 deletions pkg/cli/add_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,9 +671,37 @@ func ensureCopilotInstructions(verbose bool, skipInstructions bool) error {
return nil
}

// ensureAgenticWorkflowPrompt ensures that .github/prompts/create-agentic-workflow.prompt.md contains the agentic workflow creation prompt
// ensureAgenticWorkflowPrompt removes the old agentic workflow prompt file if it exists
func ensureAgenticWorkflowPrompt(verbose bool, skipInstructions bool) error {
return ensurePromptFromTemplate("create-agentic-workflow.prompt.md", agenticWorkflowPromptTemplate, verbose, skipInstructions)
// This function now removes the old prompt file since we've migrated to agent format
if skipInstructions {
return nil
}

gitRoot, err := findGitRoot()
if err != nil {
return err // Not in a git repository, skip
}

promptsDir := filepath.Join(gitRoot, ".github", "prompts")
oldPromptPath := filepath.Join(promptsDir, "create-agentic-workflow.prompt.md")

// Check if the old prompt file exists and remove it
if _, err := os.Stat(oldPromptPath); err == nil {
if err := os.Remove(oldPromptPath); err != nil {
return fmt.Errorf("failed to remove old prompt file: %w", err)
}
if verbose {
fmt.Printf("Removed old prompt file: %s\n", oldPromptPath)
}
}

return nil
}

// ensureAgenticWorkflowAgent ensures that .github/agents/create-agentic-workflow.md contains the agentic workflow creation agent
func ensureAgenticWorkflowAgent(verbose bool, skipInstructions bool) error {
return ensureAgentFromTemplate("create-agentic-workflow.md", agenticWorkflowAgentTemplate, verbose, skipInstructions)
}

// ensureSharedAgenticWorkflowPrompt ensures that .github/prompts/create-shared-agentic-workflow.prompt.md contains the shared workflow creation prompt
Expand Down
97 changes: 72 additions & 25 deletions pkg/cli/agentic_workflow_prompt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,26 @@ import (
"testing"
)

func TestEnsureAgenticWorkflowPrompt(t *testing.T) {
func TestEnsureAgenticWorkflowAgent(t *testing.T) {
tests := []struct {
name string
existingContent string
expectedContent string
}{
{
name: "creates new agentic workflow prompt file",
name: "creates new agentic workflow agent file",
existingContent: "",
expectedContent: strings.TrimSpace(agenticWorkflowPromptTemplate),
expectedContent: strings.TrimSpace(agenticWorkflowAgentTemplate),
},
{
name: "does not modify existing correct file",
existingContent: agenticWorkflowPromptTemplate,
expectedContent: strings.TrimSpace(agenticWorkflowPromptTemplate),
existingContent: agenticWorkflowAgentTemplate,
expectedContent: strings.TrimSpace(agenticWorkflowAgentTemplate),
},
{
name: "updates modified file",
existingContent: "# Modified Agentic Workflow Prompt\n\nThis is a modified version.",
expectedContent: strings.TrimSpace(agenticWorkflowPromptTemplate),
existingContent: "# Modified Agentic Workflow Agent\n\nThis is a modified version.",
expectedContent: strings.TrimSpace(agenticWorkflowAgentTemplate),
},
}

Expand All @@ -51,34 +51,34 @@ func TestEnsureAgenticWorkflowPrompt(t *testing.T) {
t.Fatalf("Failed to init git repo: %v", err)
}

promptsDir := filepath.Join(tempDir, ".github", "prompts")
agenticWorkflowPromptPath := filepath.Join(promptsDir, "create-agentic-workflow.prompt.md")
agentsDir := filepath.Join(tempDir, ".github", "agents")
agenticWorkflowAgentPath := filepath.Join(agentsDir, "create-agentic-workflow.md")

// Create initial content if specified
if tt.existingContent != "" {
if err := os.MkdirAll(promptsDir, 0755); err != nil {
t.Fatalf("Failed to create prompts directory: %v", err)
if err := os.MkdirAll(agentsDir, 0755); err != nil {
t.Fatalf("Failed to create agents directory: %v", err)
}
if err := os.WriteFile(agenticWorkflowPromptPath, []byte(tt.existingContent), 0644); err != nil {
t.Fatalf("Failed to create initial agentic workflow prompt: %v", err)
if err := os.WriteFile(agenticWorkflowAgentPath, []byte(tt.existingContent), 0644); err != nil {
t.Fatalf("Failed to create initial agentic workflow agent: %v", err)
}
}

// Call the function with skipInstructions=false to test the functionality
err = ensureAgenticWorkflowPrompt(false, false)
err = ensureAgenticWorkflowAgent(false, false)
if err != nil {
t.Fatalf("ensureAgenticWorkflowPrompt() returned error: %v", err)
t.Fatalf("ensureAgenticWorkflowAgent() returned error: %v", err)
}

// Check that file exists
if _, err := os.Stat(agenticWorkflowPromptPath); os.IsNotExist(err) {
t.Fatalf("Expected agentic workflow prompt file to exist")
if _, err := os.Stat(agenticWorkflowAgentPath); os.IsNotExist(err) {
t.Fatalf("Expected agentic workflow agent file to exist")
}

// Check content
content, err := os.ReadFile(agenticWorkflowPromptPath)
content, err := os.ReadFile(agenticWorkflowAgentPath)
if err != nil {
t.Fatalf("Failed to read agentic workflow prompt: %v", err)
t.Fatalf("Failed to read agentic workflow agent: %v", err)
}

contentStr := strings.TrimSpace(string(content))
Expand All @@ -93,7 +93,7 @@ func TestEnsureAgenticWorkflowPrompt(t *testing.T) {
}
}

func TestEnsureAgenticWorkflowPrompt_WithSkipInstructionsTrue(t *testing.T) {
func TestEnsureAgenticWorkflowAgent_WithSkipInstructionsTrue(t *testing.T) {
// Create a temporary directory for testing
tempDir := t.TempDir()

Expand All @@ -113,15 +113,62 @@ func TestEnsureAgenticWorkflowPrompt_WithSkipInstructionsTrue(t *testing.T) {
}

// Call the function with skipInstructions=true
err = ensureAgenticWorkflowPrompt(false, true)
err = ensureAgenticWorkflowAgent(false, true)
if err != nil {
t.Fatalf("ensureAgenticWorkflowPrompt() returned error: %v", err)
t.Fatalf("ensureAgenticWorkflowAgent() returned error: %v", err)
}

// Check that file was NOT created
agentsDir := filepath.Join(tempDir, ".github", "agents")
agenticWorkflowAgentPath := filepath.Join(agentsDir, "create-agentic-workflow.md")
if _, err := os.Stat(agenticWorkflowAgentPath); !os.IsNotExist(err) {
t.Fatalf("Expected agentic workflow agent file to NOT exist when skipInstructions=true")
}
}

func TestEnsureAgenticWorkflowPrompt_RemovesOldFile(t *testing.T) {
// Create a temporary directory for testing
tempDir := t.TempDir()

// Change to temp directory and initialize git repo for findGitRoot to work
oldWd, _ := os.Getwd()
defer func() {
_ = os.Chdir(oldWd)
}()
err := os.Chdir(tempDir)
if err != nil {
t.Fatalf("Failed to change directory: %v", err)
}

// Initialize git repo
if err := exec.Command("git", "init").Run(); err != nil {
t.Fatalf("Failed to init git repo: %v", err)
}

// Create the old prompt file
promptsDir := filepath.Join(tempDir, ".github", "prompts")
agenticWorkflowPromptPath := filepath.Join(promptsDir, "create-agentic-workflow.prompt.md")
if _, err := os.Stat(agenticWorkflowPromptPath); !os.IsNotExist(err) {
t.Fatalf("Expected agentic workflow prompt file to NOT exist when skipInstructions=true")
oldPromptPath := filepath.Join(promptsDir, "create-agentic-workflow.prompt.md")

if err := os.MkdirAll(promptsDir, 0755); err != nil {
t.Fatalf("Failed to create prompts directory: %v", err)
}
if err := os.WriteFile(oldPromptPath, []byte("old content"), 0644); err != nil {
t.Fatalf("Failed to create old prompt file: %v", err)
}

// Verify old file exists
if _, err := os.Stat(oldPromptPath); os.IsNotExist(err) {
t.Fatalf("Old prompt file should exist before test")
}

// Call the function to remove old prompt
err = ensureAgenticWorkflowPrompt(false, false)
if err != nil {
t.Fatalf("ensureAgenticWorkflowPrompt() returned error: %v", err)
}

// Check that old file was removed
if _, err := os.Stat(oldPromptPath); !os.IsNotExist(err) {
t.Fatalf("Expected old prompt file to be removed")
}
}
4 changes: 2 additions & 2 deletions pkg/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ var (
//go:embed templates/github-agentic-workflows.instructions.md
var copilotInstructionsTemplate string

//go:embed templates/create-agentic-workflow.prompt.md
var agenticWorkflowPromptTemplate string
//go:embed templates/create-agentic-workflow.md
var agenticWorkflowAgentTemplate string

//go:embed templates/create-shared-agentic-workflow.prompt.md
var sharedAgenticWorkflowPromptTemplate string
Expand Down
16 changes: 8 additions & 8 deletions pkg/cli/compile_instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ This is a test workflow for compilation.

// Define paths for instruction files
copilotInstructionsPath := filepath.Join(tempDir, ".github", "instructions", "github-agentic-workflows.instructions.md")
agenticWorkflowPromptPath := filepath.Join(tempDir, ".github", "prompts", "create-agentic-workflow.prompt.md")
agenticWorkflowAgentPath := filepath.Join(tempDir, ".github", "agents", "create-agentic-workflow.md")
sharedAgenticWorkflowPromptPath := filepath.Join(tempDir, ".github", "prompts", "create-shared-agentic-workflow.prompt.md")

// Compile the workflow
Expand Down Expand Up @@ -102,12 +102,12 @@ This is a test workflow for compilation.
t.Errorf("Expected copilot instructions file NOT to exist, but it was created at %s", copilotInstructionsPath)
}

if _, err := os.Stat(agenticWorkflowPromptPath); !os.IsNotExist(err) {
t.Errorf("Expected agentic workflow prompt file NOT to exist, but it was created at %s", agenticWorkflowPromptPath)
if _, err := os.Stat(agenticWorkflowAgentPath); !os.IsNotExist(err) {
t.Errorf("Expected agentic workflow agent file NOT to exist, but it was created at %s", agenticWorkflowAgentPath)
}

if _, err := os.Stat(sharedAgenticWorkflowPromptPath); !os.IsNotExist(err) {
t.Errorf("Expected shared agentic workflow prompt file NOT to exist, but it was created at %s", sharedAgenticWorkflowPromptPath)
t.Errorf("Expected shared agentic workflow agent file NOT to exist, but it was created at %s", sharedAgenticWorkflowPromptPath)
}
}

Expand Down Expand Up @@ -171,7 +171,7 @@ This is a test workflow for compilation.

// Define paths for instruction files
copilotInstructionsPath := filepath.Join(tempDir, ".github", "instructions", "github-agentic-workflows.instructions.md")
agenticWorkflowPromptPath := filepath.Join(tempDir, ".github", "prompts", "create-agentic-workflow.prompt.md")
agenticWorkflowAgentPath := filepath.Join(tempDir, ".github", "agents", "create-agentic-workflow.md")
sharedAgenticWorkflowPromptPath := filepath.Join(tempDir, ".github", "prompts", "create-shared-agentic-workflow.prompt.md")

// Compile all workflows (no specific files)
Expand Down Expand Up @@ -207,11 +207,11 @@ This is a test workflow for compilation.
t.Errorf("Expected copilot instructions file NOT to exist, but it was created at %s", copilotInstructionsPath)
}

if _, err := os.Stat(agenticWorkflowPromptPath); !os.IsNotExist(err) {
t.Errorf("Expected agentic workflow prompt file NOT to exist, but it was created at %s", agenticWorkflowPromptPath)
if _, err := os.Stat(agenticWorkflowAgentPath); !os.IsNotExist(err) {
t.Errorf("Expected agentic workflow agent file NOT to exist, but it was created at %s", agenticWorkflowAgentPath)
}

if _, err := os.Stat(sharedAgenticWorkflowPromptPath); !os.IsNotExist(err) {
t.Errorf("Expected shared agentic workflow prompt file NOT to exist, but it was created at %s", sharedAgenticWorkflowPromptPath)
t.Errorf("Expected shared agentic workflow agent file NOT to exist, but it was created at %s", sharedAgenticWorkflowPromptPath)
}
}
50 changes: 50 additions & 0 deletions pkg/cli/copilot-prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,53 @@ func ensurePromptFromTemplate(promptFileName, templateContent string, verbose bo

return nil
}

// ensureAgentFromTemplate ensures that an agent file exists and matches the embedded template
func ensureAgentFromTemplate(agentFileName, templateContent string, verbose bool, skipInstructions bool) error {
if skipInstructions {
return nil // Skip writing agent if flag is set
}

gitRoot, err := findGitRoot()
if err != nil {
return err // Not in a git repository, skip
}

agentsDir := filepath.Join(gitRoot, ".github", "agents")
agentPath := filepath.Join(agentsDir, agentFileName)

// Ensure the .github/agents directory exists
if err := os.MkdirAll(agentsDir, 0755); err != nil {
return fmt.Errorf("failed to create .github/agents directory: %w", err)
}

// Check if the agent file already exists and matches the template
existingContent := ""
if content, err := os.ReadFile(agentPath); err == nil {
existingContent = string(content)
}

// Check if content matches our expected template
expectedContent := strings.TrimSpace(templateContent)
if strings.TrimSpace(existingContent) == expectedContent {
if verbose {
fmt.Printf("Agent is up-to-date: %s\n", agentPath)
}
return nil
}

// Write the agent file
if err := os.WriteFile(agentPath, []byte(templateContent), 0644); err != nil {
return fmt.Errorf("failed to write agent file: %w", err)
}

if verbose {
if existingContent == "" {
fmt.Printf("Created agent: %s\n", agentPath)
} else {
fmt.Printf("Updated agent: %s\n", agentPath)
}
}

return nil
}
21 changes: 14 additions & 7 deletions pkg/cli/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,21 @@ func InitRepository(verbose bool, mcp bool) error {
fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Created GitHub Copilot instructions"))
}

// Write agentic workflow prompt
initLog.Print("Writing agentic workflow prompt")
// Remove old agentic workflow prompt if it exists
initLog.Print("Removing old agentic workflow prompt")
if err := ensureAgenticWorkflowPrompt(verbose, false); err != nil {
initLog.Printf("Failed to write agentic workflow prompt: %v", err)
return fmt.Errorf("failed to write agentic workflow prompt: %w", err)
initLog.Printf("Failed to remove old agentic workflow prompt: %v", err)
return fmt.Errorf("failed to remove old agentic workflow prompt: %w", err)
}

// Write agentic workflow agent
initLog.Print("Writing agentic workflow agent")
if err := ensureAgenticWorkflowAgent(verbose, false); err != nil {
initLog.Printf("Failed to write agentic workflow agent: %v", err)
return fmt.Errorf("failed to write agentic workflow agent: %w", err)
}
if verbose {
fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Created /create-agentic-workflow command"))
fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Created custom agent for workflow creation"))
}

// Write shared agentic workflow prompt
Expand Down Expand Up @@ -105,9 +112,9 @@ func InitRepository(verbose bool, mcp bool) error {
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("✓ GitHub Copilot Agent MCP integration configured"))
fmt.Fprintln(os.Stderr, "")
}
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Start a chat and copy the following prompt to create a new workflow:"))
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Start a chat and use the custom agent to create a new workflow:"))
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, " activate @.github/prompts/create-agentic-workflow.prompt.md")
fmt.Fprintln(os.Stderr, " @.github/agents/create-agentic-workflow.md")
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Or add workflows from the catalog: "+constants.CLIExtensionPrefix+" add <workflow-name>"))
fmt.Fprintln(os.Stderr, "")
Expand Down
Loading
Loading