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

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

553 changes: 114 additions & 439 deletions .github/workflows/dev.lock.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .github/workflows/dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
push:
branches:
- copilot/*
engine: claude
engine: copilot
safe-outputs:
staged: true
safe-jobs:
Expand Down
6 changes: 3 additions & 3 deletions cmd/gh-aw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ var verbose bool

// validateEngine validates the engine flag value
func validateEngine(engine string) error {
if engine != "" && engine != "claude" && engine != "codex" {
return fmt.Errorf("invalid engine value '%s'. Must be 'claude' or 'codex'", engine)
if engine != "" && engine != "claude" && engine != "codex" && engine != "copilot" {
return fmt.Errorf("invalid engine value '%s'. Must be 'claude', 'codex', or 'copilot'", engine)
}
return nil
}
Expand Down Expand Up @@ -285,7 +285,7 @@ func init() {
uninstallCmd.Flags().BoolP("local", "l", false, "Uninstall packages from local .aw/packages instead of global ~/.aw/packages")

// Add AI flag to compile and add commands
compileCmd.Flags().StringP("engine", "a", "", "Override AI engine (claude, codex)")
compileCmd.Flags().StringP("engine", "a", "", "Override AI engine (claude, codex, copilot)")
compileCmd.Flags().Bool("validate", true, "Enable GitHub Actions workflow schema validation (default: true)")
compileCmd.Flags().BoolP("watch", "w", false, "Watch for changes to workflow files and recompile automatically")
compileCmd.Flags().String("workflows-dir", "", "Relative directory containing workflows (default: .github/workflows)")
Expand Down
7 changes: 6 additions & 1 deletion cmd/gh-aw/main_entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ func TestValidateEngine(t *testing.T) {
engine: "codex",
expectErr: false,
},
{
name: "valid copilot engine",
engine: "copilot",
expectErr: false,
},
{
name: "invalid engine",
engine: "gpt4",
Expand Down Expand Up @@ -75,7 +80,7 @@ func TestValidateEngine(t *testing.T) {
return
}

if tt.errMessage != "" && err.Error() != fmt.Sprintf("invalid engine value '%s'. Must be 'claude' or 'codex'", tt.engine) {
if tt.errMessage != "" && err.Error() != fmt.Sprintf("invalid engine value '%s'. Must be 'claude', 'codex', or 'copilot'", tt.engine) {
t.Errorf("validateEngine(%q) error message = %v, want to contain %v", tt.engine, err.Error(), tt.errMessage)
}
} else {
Expand Down
30 changes: 22 additions & 8 deletions docs/src/content/docs/reference/engines.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ sidebar:

GitHub Agentic Workflows support multiple AI engines to interpret and execute natural language instructions. Each engine has unique capabilities and configuration options.

## Available Engines
## Agentic Engines

### Claude (Default)
### Anthropic Claude Code (Default)

Claude Code is the default and recommended AI engine for most workflows. It excels at reasoning, code analysis, and understanding complex contexts.

Expand All @@ -29,13 +29,23 @@ engine:
DEBUG_MODE: "true"
```

**Features:**
- Excellent reasoning and code analysis capabilities
- Supports max-turns for cost control
- Uses MCP servers for tool integration
- Generates `mcp-servers.json` configuration
#### Secrets

- `ANTHROPIC_API_KEY` secret is required for authentication.

### GitHub Copilot (Experimental)

### Codex (Experimental)
[GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/use-copilot-cli)

```yaml
engine: copilot
```

#### Secrets

- `COPILOT_CLI_TOKEN ` secret is required for authentication.

### OpenAI Codex (Experimental)

OpenAI Codex CLI with MCP server support. Designed for code-focused tasks and integration scenarios.

Expand Down Expand Up @@ -72,6 +82,10 @@ engine:
- **`user-agent`** (optional): Custom user agent string for GitHub MCP server configuration
- **`config`** (optional): Additional TOML configuration text appended to generated config.toml

#### Secrets

- `OPENAI_API_KEY` secret is required for authentication.

### Custom Engine

For advanced users who want to define completely custom GitHub Actions steps instead of using AI interpretation.
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/tools/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ gh aw logs --start-date -1mo # Last month's runs
# Filter by AI engine type
gh aw logs --engine claude # Only Claude workflows
gh aw logs --engine codex # Only Codex workflows
gh aw logs --engine copilot # Only Copilot workflows

# Filter by branch name
gh aw logs --branch main # Only runs from main branch
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/add_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ It's a shortcut for:
cmd.Flags().StringP("name", "n", "", "Specify name for the added workflow (without .md extension)")

// Add AI flag to add command
cmd.Flags().StringP("engine", "a", "", "Override AI engine (claude, codex)")
cmd.Flags().StringP("engine", "a", "", "Override AI engine (claude, codex, copilot, custom)")

// Add repository flag to add command
cmd.Flags().StringP("repo", "r", "", "Install and use workflows from specified repository (org/repo)")
Expand Down
1 change: 1 addition & 0 deletions pkg/cli/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func (b *InteractiveWorkflowBuilder) promptForTrigger() error {
// promptForEngine asks the user to select the AI engine
func (b *InteractiveWorkflowBuilder) promptForEngine() error {
engineOptions := []huh.Option[string]{
huh.NewOption("copilot - GitHub Copilot CLI", "copilot"),
huh.NewOption("claude - Anthropic Claude Code coding agent", "claude"),
huh.NewOption("codex - OpenAI Codex engine", "codex"),
huh.NewOption("custom - Custom engine configuration", "custom"),
Expand Down
8 changes: 5 additions & 3 deletions pkg/cli/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ Examples:
` + constants.CLIExtensionPrefix + ` logs --start-date -1mo # Filter runs from last month
` + constants.CLIExtensionPrefix + ` logs --engine claude # Filter logs by claude engine
` + constants.CLIExtensionPrefix + ` logs --engine codex # Filter logs by codex engine
` + constants.CLIExtensionPrefix + ` logs --engine copilot # Filter logs by copilot engine
` + constants.CLIExtensionPrefix + ` logs -o ./my-logs # Custom output directory
` + constants.CLIExtensionPrefix + ` logs --branch main # Filter logs by branch name
` + constants.CLIExtensionPrefix + ` logs --branch feature-xyz # Filter logs by feature branch
` + constants.CLIExtensionPrefix + ` logs --after-run-id 1000 # Filter runs after run ID 1000
Expand Down Expand Up @@ -257,7 +259,7 @@ Examples:
logsCmd.Flags().String("start-date", "", "Filter runs created after this date (YYYY-MM-DD or delta like -1d, -1w, -1mo)")
logsCmd.Flags().String("end-date", "", "Filter runs created before this date (YYYY-MM-DD or delta like -1d, -1w, -1mo)")
logsCmd.Flags().StringP("output", "o", "./logs", "Output directory for downloaded logs and artifacts")
logsCmd.Flags().String("engine", "", "Filter logs by agentic engine type (claude, codex)")
logsCmd.Flags().String("engine", "", "Filter logs by agentic engine type (claude, codex, copilot)")
logsCmd.Flags().String("branch", "", "Filter runs by branch name (e.g., main, feature-branch)")
logsCmd.Flags().Int64("before-run-id", 0, "Filter runs with database ID before this value (exclusive)")
logsCmd.Flags().Int64("after-run-id", 0, "Filter runs with database ID after this value (exclusive)")
Expand Down Expand Up @@ -357,7 +359,7 @@ func DownloadWorkflowLogs(workflowName string, count int, startDate, endDate, ou
if detectedEngine != nil {
// Get the engine ID to compare with the filter
registry := workflow.GetGlobalEngineRegistry()
for _, supportedEngine := range []string{"claude", "codex"} {
for _, supportedEngine := range constants.AgenticEngines {
if testEngine, err := registry.GetEngine(supportedEngine); err == nil && testEngine == detectedEngine {
engineMatches = (supportedEngine == engine)
break
Expand All @@ -371,7 +373,7 @@ func DownloadWorkflowLogs(workflowName string, count int, startDate, endDate, ou
if detectedEngine != nil {
// Try to get a readable name for the detected engine
registry := workflow.GetGlobalEngineRegistry()
for _, supportedEngine := range []string{"claude", "codex"} {
for _, supportedEngine := range constants.AgenticEngines {
if testEngine, err := registry.GetEngine(supportedEngine); err == nil && testEngine == detectedEngine {
engineName = supportedEngine
break
Expand Down
7 changes: 6 additions & 1 deletion pkg/cli/logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,11 @@ func TestDownloadWorkflowLogsWithEngineFilter(t *testing.T) {
engine: "codex",
expectError: false,
},
{
name: "valid copilot engine",
engine: "copilot",
expectError: false,
},
{
name: "empty engine (no filter)",
engine: "",
Expand Down Expand Up @@ -864,7 +869,7 @@ func TestLogsCommandFlags(t *testing.T) {
t.Fatal("Engine flag not found")
}

if engineFlag.Usage != "Filter logs by agentic engine type (claude, codex)" {
if engineFlag.Usage != "Filter logs by agentic engine type (claude, codex, copilot)" {
t.Errorf("Unexpected engine flag usage text: %s", engineFlag.Usage)
}

Expand Down
9 changes: 5 additions & 4 deletions pkg/cli/templates/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ The YAML frontmatter supports these fields:
### Agentic Workflow Specific Fields

- **`engine:`** - AI processor configuration
- String format: `"claude"` (default), `"codex"`, `"custom"` (⚠️ experimental)
- String format: `"claude"` (default), `"codex"`, `"copilot"`, `"custom"` (⚠️ experimental)
- Object format for extended configuration:
```yaml
engine:
id: claude # Required: coding agent identifier (claude, codex, custom)
id: claude # Required: coding agent identifier (claude, codex, copilot, custom)
version: beta # Optional: version of the action (has sensible default)
model: claude-3-5-sonnet-20241022 # Optional: LLM model to use (has sensible default)
max-turns: 5 # Optional: maximum chat iterations per run (has sensible default)
Expand Down Expand Up @@ -184,7 +184,7 @@ The YAML frontmatter supports these fields:
```
Useful when you need additional permissions or want to perform actions across repositories.

- **`alias:`** - Alternative workflow name (string)
- **`command:`** - Command trigger configuration for /mention workflows
- **`cache:`** - Cache configuration for workflow dependencies (object or array)
- **`cache-memory:`** - Memory MCP server with persistent cache storage (boolean or object)

Expand Down Expand Up @@ -795,6 +795,7 @@ gh aw logs weekly-research
# Filter logs by AI engine type
gh aw logs --engine claude # Only Claude workflows
gh aw logs --engine codex # Only Codex workflows
gh aw logs --engine copilot # Only Copilot workflows

# Limit number of runs and filter by date (absolute dates)
gh aw logs -c 10 --start-date 2024-01-01 --end-date 2024-01-31
Expand Down Expand Up @@ -932,7 +933,7 @@ The workflow frontmatter is validated against JSON Schema during compilation. Co

- **Invalid field names** - Only fields in the schema are allowed
- **Wrong field types** - e.g., `timeout_minutes` must be integer
- **Invalid enum values** - e.g., `engine` must be "claude", "codex", or "custom"
- **Invalid enum values** - e.g., `engine` must be "claude", "codex", "copilot" or "custom"
- **Missing required fields** - Some triggers require specific configuration

Use `gh aw compile --verbose` to see detailed validation messages, or `gh aw compile <workflow-id> --verbose` to validate a specific workflow.
Expand Down
2 changes: 2 additions & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,5 @@ var AllowedExpressions = []string{
const AgentJobName = "agent"
const SafeOutputArtifactName = "safe_output.jsonl"
const AgentOutputArtifactName = "agent_output.json"

var AgenticEngines = []string{"claude", "codex", "copilot"}
8 changes: 5 additions & 3 deletions pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -817,9 +817,10 @@
"enum": [
"claude",
"codex",
"copilot",
"custom"
],
"description": "Simple engine name (claude, codex, or custom)"
"description": "Simple engine name (claude, codex, copilot or custom)"
},
{
"type": "object",
Expand All @@ -830,9 +831,10 @@
"enum": [
"claude",
"codex",
"custom"
"custom",
"copilot"
],
"description": "Agent CLI identifier (claude, codex, or custom)"
"description": "Agent CLI identifier (claude, codex, copilot, or custom)"
},
"version": {
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions pkg/workflow/agentic_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ func NewEngineRegistry() *EngineRegistry {
// Register built-in engines
registry.Register(NewClaudeEngine())
registry.Register(NewCodexEngine())
registry.Register(NewCopilotEngine())
registry.Register(NewCustomEngine())

return registry
Expand Down
8 changes: 4 additions & 4 deletions pkg/workflow/agentic_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ func TestEngineRegistry(t *testing.T) {

// Test that built-in engines are registered
supportedEngines := registry.GetSupportedEngines()
if len(supportedEngines) != 3 {
t.Errorf("Expected 3 supported engines, got %d", len(supportedEngines))
if len(supportedEngines) != 4 {
t.Errorf("Expected 4 supported engines, got %d", len(supportedEngines))
}

// Test getting engines by ID
Expand Down Expand Up @@ -116,7 +116,7 @@ func TestEngineRegistryCustomEngine(t *testing.T) {

// Test that supported engines list is updated
supportedEngines := registry.GetSupportedEngines()
if len(supportedEngines) != 4 {
t.Errorf("Expected 4 supported engines after adding test-custom, got %d", len(supportedEngines))
if len(supportedEngines) != 5 {
t.Errorf("Expected 5 supported engines after adding test-custom, got %d", len(supportedEngines))
}
}
Loading