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
5 changes: 3 additions & 2 deletions .github/aw/subagents.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ description: Guide for defining inline sub-agents in workflow markdown files —

Inline sub-agents let you define specialised agents directly inside a workflow markdown file. At runtime the sub-agent sections are extracted from the prompt (after `{{#runtime-import}}` macros are resolved) and written to the engine-specific agents directory so the engine CLI can discover and invoke them.

> **Experimental feature.** Compilation emits `⚠ Using experimental feature: inline-sub-agents` whenever a workflow contains at least one `## agent:` block.

---

## Enabling the Feature
Expand All @@ -21,6 +19,8 @@ engine: copilot
```

> `features.inline-agents` is deprecated and no longer needed. Existing workflows may still include it, but it has no effect.
>
> `inline-sub-agents: false` is not supported and fails compilation. Remove the field.

---

Expand Down Expand Up @@ -200,4 +200,5 @@ changes. Return a bulleted list, one bullet per file.
- Sub-agents do not support `engine:`, `tools:`, `network:`, or `mcp-servers:` fields — those are stripped at runtime.
- Sub-agents cannot define their own safe-output jobs.
- `features.inline-agents` is deprecated and has no effect; inline sub-agent upload/restore is always generated.
- `inline-sub-agents: false` is rejected at compile time; inline sub-agents cannot be disabled.
- Sub-agent blocks must appear in the main workflow file body; they are not resolved inside imported shared files.
4 changes: 1 addition & 3 deletions docs/src/content/docs/patterns/data-ops.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,9 @@ main agent: → orchestrates sub-agents, synthesizes final report (high-reas

### Enabling inline sub-agents

Add the `inline-agents` feature flag and the `cli-proxy` tool so sub-agents can make authenticated GitHub API calls:
Inline sub-agents are enabled by default. Add `cli-proxy` so sub-agents can make authenticated GitHub API calls:

```yaml
features:
inline-agents: true
tools:
cli-proxy: true
```
Expand Down
2 changes: 2 additions & 0 deletions docs/src/content/docs/reference/inline-sub-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ sidebar:

An inline sub-agent is a named agent definition embedded directly in a workflow markdown file. Instead of creating a separate file in `.github/agents/`, you define the agent's frontmatter and instructions in a dedicated section of the same workflow file.

Inline sub-agents are enabled by default. `features.inline-agents` is deprecated/no-op, and `inline-sub-agents: false` is rejected at compile time.

## Syntax

Start a sub-agent block with a level-2 heading in the following form:
Expand Down
1 change: 1 addition & 0 deletions pkg/cli/codemod_inline_agents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

func TestInlineAgentsFeatureRemovalCodemod(t *testing.T) {
codemod := getInlineAgentsFeatureRemovalCodemod()
assert.Equal(t, "1.0.0", codemod.IntroducedIn)

tests := []struct {
name string
Expand Down
5 changes: 5 additions & 0 deletions pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2720,6 +2720,11 @@
}
]
},
"inline-sub-agents": {
"type": "boolean",
"description": "Deprecated switch for inline sub-agent support. Inline sub-agents are enabled by default. Setting this to false is not supported and causes a compilation error.",
"examples": [true]
},
"features": {
"description": "Feature flags and configuration options for experimental or optional features in the workflow. Each feature can be a boolean flag or a string value. The 'action-tag' feature (string) specifies the tag or SHA to use when referencing actions/setup in compiled workflows (for testing purposes only).",
"type": "object",
Expand Down
6 changes: 1 addition & 5 deletions pkg/workflow/compiler_orchestrator_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,7 @@ func (c *Compiler) processToolsAndMarkdown(result *parser.FrontmatterResult, cle
return nil, fmt.Errorf("failed to extract inline sub-agents: %w", err)
}
orchestratorToolsLog.Printf("Effective markdown after stripping sub-agent sections: %d bytes", len(effectiveMarkdown))
if len(subAgents) > 0 {
fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Using experimental feature: inline-sub-agents"))
c.IncrementWarningCount()
}

orchestratorToolsLog.Printf("Extracted inline sub-agents: count=%d", len(subAgents))
// Surface best-effort sub-agent frontmatter warnings collected during import BFS traversal.
for _, w := range importsResult.Warnings {
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(w))
Expand Down
1 change: 1 addition & 0 deletions pkg/workflow/compiler_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ type WorkflowData struct {
ActionMode ActionMode // action mode for workflow compilation (dev, release, script)
HasExplicitGitHubTool bool // true if tools.github was explicitly configured in frontmatter
InlinedImports bool // if true, inline all imports at compile time (from inlined-imports frontmatter field)
InlineSubAgentsDisabled bool // true when inline-sub-agents: false is set in frontmatter (rejected at compile time)
CheckoutConfigs []*CheckoutConfig // user-configured checkout settings from frontmatter
CheckoutDisabled bool // true when checkout: false is set in frontmatter
HasDispatchItemNumber bool // true when workflow_dispatch has item_number input (generated by label trigger shorthand)
Expand Down
6 changes: 6 additions & 0 deletions pkg/workflow/compiler_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ func (c *Compiler) validateFeatureConfig(workflowData *WorkflowData, markdownPat
return formatCompilerError(markdownPath, "error", err.Error(), err)
}

// Inline sub-agents are always enabled and can no longer be disabled.
if workflowData.InlineSubAgentsDisabled {
msg := "inline-sub-agents: false is not supported. Inline sub-agents are always enabled. Remove inline-sub-agents from your frontmatter."
return formatCompilerError(markdownPath, "error", msg, errors.New("inline-sub-agents cannot be set to false"))
}

// Check for action-mode feature flag override
if workflowData.Features != nil {
if actionModeVal, exists := workflowData.Features["action-mode"]; exists {
Expand Down
34 changes: 24 additions & 10 deletions pkg/workflow/compiler_validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,33 +67,38 @@ func TestValidateFeatureConfig(t *testing.T) {
tests := []struct {
name string
features map[string]any
inlineDisable bool
shouldError bool
errorContains string
}{
{
name: "no features",
features: nil,
shouldError: false,
name: "no features",
features: nil,
inlineDisable: false,
shouldError: false,
},
{
name: "valid action-mode dev",
features: map[string]any{
"action-mode": "dev",
},
shouldError: false,
inlineDisable: false,
shouldError: false,
},
{
name: "valid action-mode release",
features: map[string]any{
"action-mode": "release",
},
shouldError: false,
inlineDisable: false,
shouldError: false,
},
{
name: "invalid action-mode",
features: map[string]any{
"action-mode": "invalid-mode",
},
inlineDisable: false,
shouldError: true,
errorContains: "invalid action-mode feature flag",
},
Expand All @@ -102,7 +107,15 @@ func TestValidateFeatureConfig(t *testing.T) {
features: map[string]any{
"action-mode": "",
},
shouldError: false,
inlineDisable: false,
shouldError: false,
},
{
name: "inline-sub-agents false is rejected",
features: nil,
inlineDisable: true,
shouldError: true,
errorContains: "inline-sub-agents: false is not supported",
},
}

Expand All @@ -113,10 +126,11 @@ func TestValidateFeatureConfig(t *testing.T) {

compiler := NewCompiler()
workflowData := &WorkflowData{
Name: "Test",
MarkdownContent: "# Test",
AI: "copilot",
Features: tt.features,
Name: "Test",
MarkdownContent: "# Test",
AI: "copilot",
Features: tt.features,
InlineSubAgentsDisabled: tt.inlineDisable,
}

err := compiler.validateFeatureConfig(workflowData, markdownPath)
Expand Down
3 changes: 3 additions & 0 deletions pkg/workflow/frontmatter_serialization.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,9 @@ func (fc *FrontmatterConfig) ToMap() map[string]any {
if fc.Features != nil {
result["features"] = fc.Features
}
if fc.InlineSubAgents != nil {
result["inline-sub-agents"] = *fc.InlineSubAgents
}
if fc.Env != nil {
result["env"] = fc.Env
}
Expand Down
9 changes: 6 additions & 3 deletions pkg/workflow/frontmatter_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,12 @@ type FrontmatterConfig struct {
Sandbox *SandboxConfig `json:"sandbox,omitempty"`

// Feature flags and other settings
Features map[string]any `json:"features,omitempty"` // Dynamic feature flags
Env map[string]string `json:"env,omitempty"`
Secrets map[string]any `json:"secrets,omitempty"`
Features map[string]any `json:"features,omitempty"` // Dynamic feature flags
// Deprecated: as of v1.1.0, inline sub-agents are always enabled.
// Remove this field from frontmatter. Setting false causes a compilation error.
InlineSubAgents *bool `json:"inline-sub-agents,omitempty"`
Env map[string]string `json:"env,omitempty"`
Secrets map[string]any `json:"secrets,omitempty"`

// Workflow execution settings
RunsOn string `json:"runs-on,omitempty"`
Expand Down
18 changes: 18 additions & 0 deletions pkg/workflow/frontmatter_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@ func TestParseFrontmatterConfig(t *testing.T) {
}
})

t.Run("parses inline-sub-agents boolean", func(t *testing.T) {
frontmatter := map[string]any{
"inline-sub-agents": false,
}

config, err := ParseFrontmatterConfig(frontmatter)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

if config.InlineSubAgents == nil {
t.Fatal("InlineSubAgents should not be nil")
}
if *config.InlineSubAgents {
t.Error("InlineSubAgents should be false")
}
})

t.Run("parses complete workflow config", func(t *testing.T) {
frontmatter := map[string]any{
"name": "full-workflow",
Expand Down
11 changes: 11 additions & 0 deletions pkg/workflow/workflow_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ func (c *Compiler) buildInitialWorkflowData(
}
}

// Populate inline-sub-agents disable flag: explicit false is rejected during validation.
if toolsResult.parsedFrontmatter != nil && toolsResult.parsedFrontmatter.InlineSubAgents != nil {
workflowData.InlineSubAgentsDisabled = !*toolsResult.parsedFrontmatter.InlineSubAgents
} else if rawVal, ok := result.Frontmatter["inline-sub-agents"]; ok {
// Fall back to raw frontmatter parsing when full ParseFrontmatterConfig fails
// (e.g. due to unrecognized config shapes in other frontmatter sections).
if boolVal, ok := rawVal.(bool); ok {
workflowData.InlineSubAgentsDisabled = !boolVal
}
}

// Populate stale-check flag: disabled when on.stale-check: false is set in frontmatter.
if onVal, ok := result.Frontmatter["on"]; ok {
if onMap, ok := onVal.(map[string]any); ok {
Expand Down