diff --git a/pkg/cli/compile_compiler_setup.go b/pkg/cli/compile_compiler_setup.go
index a4afde117a8..bb5ac9a9994 100644
--- a/pkg/cli/compile_compiler_setup.go
+++ b/pkg/cli/compile_compiler_setup.go
@@ -201,7 +201,7 @@ func validateActionModeConfig(actionMode string) error {
 
 	mode := workflow.ActionMode(actionMode)
 	if !mode.IsValid() {
-		return fmt.Errorf("invalid action mode '%s'. Must be 'dev', 'release', or 'script'", actionMode)
+		return fmt.Errorf("invalid action mode '%s'. Must be 'dev', 'release', 'script', or 'action'", actionMode)
 	}
 
 	return nil
diff --git a/pkg/cli/copilot_setup.go b/pkg/cli/copilot_setup.go
index 5c6fbc62545..c0236f25c3d 100644
--- a/pkg/cli/copilot_setup.go
+++ b/pkg/cli/copilot_setup.go
@@ -15,7 +15,7 @@ import (
 var copilotSetupLog = logger.New("cli:copilot_setup")
 
 // getActionRef returns the action reference string based on action mode and version.
-// If a resolver is provided and mode is release, attempts to resolve the SHA for a SHA-pinned reference.
+// If a resolver is provided and mode is release or action, attempts to resolve the SHA for a SHA-pinned reference.
 // Falls back to a version tag reference if SHA resolution fails or resolver is nil.
 func getActionRef(actionMode workflow.ActionMode, version string, resolver workflow.ActionSHAResolver) string {
 	if actionMode.IsRelease() && version != "" && version != "dev" {
@@ -28,16 +28,30 @@ func getActionRef(actionMode workflow.ActionMode, version string, resolver workf
 		}
 		return "@" + version
 	}
+	if actionMode.IsAction() && version != "" && version != "dev" {
+		if resolver != nil {
+			sha, err := resolver.ResolveSHA("github/gh-aw-actions/setup-cli", version)
+			if err == nil && sha != "" {
+				return fmt.Sprintf("@%s # %s", sha, version)
+			}
+			copilotSetupLog.Printf("Failed to resolve SHA for gh-aw-actions/setup-cli@%s: %v, falling back to version tag", version, err)
+		}
+		return "@" + version
+	}
 	return "@main"
 }
 
 // generateCopilotSetupStepsYAML generates the copilot-setup-steps.yml content based on action mode
 func generateCopilotSetupStepsYAML(actionMode workflow.ActionMode, version string, resolver workflow.ActionSHAResolver) string {
-	// Determine the action reference - use SHA-pinned or version tag in release mode, @main in dev mode
+	// Determine the action reference - use SHA-pinned or version tag in release/action mode, @main in dev mode
 	actionRef := getActionRef(actionMode, version, resolver)
 
-	if actionMode.IsRelease() {
-		// Use the actions/setup-cli action in release mode
+	if actionMode.IsRelease() || actionMode.IsAction() {
+		// Determine the action repo based on mode
+		actionRepo := "github/gh-aw/actions/setup-cli"
+		if actionMode.IsAction() {
+			actionRepo = "github/gh-aw-actions/setup-cli"
+		}
 		return fmt.Sprintf(`name: "Copilot Setup Steps"
 
 # This workflow configures the environment for GitHub Copilot Agent with gh-aw MCP server
@@ -61,10 +75,10 @@ jobs:
       - name: Checkout repository
         uses: actions/checkout@v6
       - name: Install gh-aw extension
-        uses: github/gh-aw/actions/setup-cli%s
+        uses: %s%s
         with:
           version: %s
-`, actionRef, version)
+`, actionRepo, actionRef, version)
 	}
 
 	// Default (dev/script mode): use curl to download install script
@@ -158,9 +172,9 @@ func upgradeCopilotSetupSteps(verbose bool, actionMode workflow.ActionMode, vers
 func ensureCopilotSetupStepsWithUpgrade(verbose bool, actionMode workflow.ActionMode, version string, upgradeVersion bool) error {
 	copilotSetupLog.Printf("Creating copilot-setup-steps.yml with action mode: %s, version: %s, upgradeVersion: %v", actionMode, version, upgradeVersion)
 
-	// Create a SHA resolver for release mode to enable SHA-pinned action references
+	// Create a SHA resolver for release/action mode to enable SHA-pinned action references
 	var resolver workflow.ActionSHAResolver
-	if actionMode.IsRelease() {
+	if actionMode.IsRelease() || actionMode.IsAction() {
 		cache := workflow.NewActionCache(".")
 		_ = cache.Load() // Ignore errors if cache doesn't exist yet
 		resolver = workflow.NewActionResolver(cache)
@@ -259,11 +273,15 @@ func renderCopilotSetupUpdateInstructions(filePath string, actionMode workflow.A
 	// Determine the action reference
 	actionRef := getActionRef(actionMode, version, resolver)
 
-	if actionMode.IsRelease() {
+	if actionMode.IsRelease() || actionMode.IsAction() {
+		actionRepo := "github/gh-aw/actions/setup-cli"
+		if actionMode.IsAction() {
+			actionRepo = "github/gh-aw-actions/setup-cli"
+		}
 		fmt.Fprintln(os.Stderr, "      - name: Checkout repository")
 		fmt.Fprintln(os.Stderr, "        uses: actions/checkout@v6")
 		fmt.Fprintf(os.Stderr, "      - name: Install gh-aw extension\n")
-		fmt.Fprintf(os.Stderr, "        uses: github/gh-aw/actions/setup-cli%s\n", actionRef)
+		fmt.Fprintf(os.Stderr, "        uses: %s%s\n", actionRepo, actionRef)
 		fmt.Fprintln(os.Stderr, "        with:")
 		fmt.Fprintf(os.Stderr, "          version: %s\n", version)
 	} else {
@@ -274,11 +292,12 @@ func renderCopilotSetupUpdateInstructions(filePath string, actionMode workflow.A
 	fmt.Fprintln(os.Stderr)
 }
 
-// setupCliUsesPattern matches the uses: line for github/gh-aw/actions/setup-cli.
+// setupCliUsesPattern matches the uses: line for either github/gh-aw/actions/setup-cli
+// or github/gh-aw-actions/setup-cli.
 // It handles unquoted version-tag refs, unquoted SHA-pinned refs (with trailing comment),
 // and quoted refs produced by some YAML marshalers (e.g. "...@sha # vX.Y.Z").
 var setupCliUsesPattern = regexp.MustCompile(
-	`(?m)^(\s+uses:[ \t]*)"?(github/gh-aw/actions/setup-cli@[^"\n]*)"?([ \t]*)$`)
+	`(?m)^(\s+uses:[ \t]*)"?(github/gh-aw(?:-actions)?/(?:actions/)?setup-cli@[^"\n]*)"?([ \t]*)$`)
 
 // upgradeSetupCliVersionInContent replaces the setup-cli action reference and the
 // associated version: parameter in the raw YAML content using targeted regex
@@ -287,7 +306,7 @@ var setupCliUsesPattern = regexp.MustCompile(
 // Returns (upgraded, updatedContent, error).  upgraded is false when no change
 // was required (e.g. already at the target version, or file has no setup-cli step).
 func upgradeSetupCliVersionInContent(content []byte, actionMode workflow.ActionMode, version string, resolver workflow.ActionSHAResolver) (bool, []byte, error) {
-	if !actionMode.IsRelease() {
+	if !actionMode.IsRelease() && !actionMode.IsAction() {
 		return false, content, nil
 	}
 
@@ -296,7 +315,11 @@ func upgradeSetupCliVersionInContent(content []byte, actionMode workflow.ActionM
 	}
 
 	actionRef := getActionRef(actionMode, version, resolver)
-	newUses := "github/gh-aw/actions/setup-cli" + actionRef
+	actionRepo := "github/gh-aw/actions/setup-cli"
+	if actionMode.IsAction() {
+		actionRepo = "github/gh-aw-actions/setup-cli"
+	}
+	newUses := actionRepo + actionRef
 
 	// Replace the uses: line, stripping any surrounding quotes in the process.
 	updated := setupCliUsesPattern.ReplaceAll(content, []byte("${1}"+newUses+"${3}"))
diff --git a/pkg/workflow/action_mode.go b/pkg/workflow/action_mode.go
index c5ed584b27f..acd71931cfe 100644
--- a/pkg/workflow/action_mode.go
+++ b/pkg/workflow/action_mode.go
@@ -21,6 +21,9 @@ const (
 
 	// ActionModeScript runs setup.sh script from checked-out .github folder instead of using action steps
 	ActionModeScript ActionMode = "script"
+
+	// ActionModeAction references custom actions from the github/gh-aw-actions repository using the same release version
+	ActionModeAction ActionMode = "action"
 )
 
 // String returns the string representation of the action mode
@@ -30,7 +33,7 @@ func (m ActionMode) String() string {
 
 // IsValid checks if the action mode is valid
 func (m ActionMode) IsValid() bool {
-	return m == ActionModeDev || m == ActionModeRelease || m == ActionModeScript
+	return m == ActionModeDev || m == ActionModeRelease || m == ActionModeScript || m == ActionModeAction
 }
 
 // IsDev returns true if the action mode is development mode
@@ -48,6 +51,11 @@ func (m ActionMode) IsScript() bool {
 	return m == ActionModeScript
 }
 
+// IsAction returns true if the action mode is action mode (uses github/gh-aw-actions repo)
+func (m ActionMode) IsAction() bool {
+	return m == ActionModeAction
+}
+
 // UsesExternalActions returns true (always true since inline mode was removed)
 func (m ActionMode) UsesExternalActions() bool {
 	return true
diff --git a/pkg/workflow/action_reference.go b/pkg/workflow/action_reference.go
index 99480db43c0..a1228321f53 100644
--- a/pkg/workflow/action_reference.go
+++ b/pkg/workflow/action_reference.go
@@ -12,6 +12,9 @@ var actionRefLog = logger.New("workflow:action_reference")
 const (
 	// GitHubOrgRepo is the organization and repository name for custom action references
 	GitHubOrgRepo = "github/gh-aw"
+
+	// GitHubActionsOrgRepo is the organization and repository name for the external gh-aw-actions repository
+	GitHubActionsOrgRepo = "github/gh-aw-actions"
 )
 
 // ResolveSetupActionReference resolves the actions/setup action reference based on action mode and version.
@@ -19,8 +22,8 @@ const (
 // workflow generators (like maintenance workflow) that don't have access to WorkflowData.
 //
 // Parameters:
-//   - actionMode: The action mode (dev or release)
-//   - version: The version string to use for release mode
+//   - actionMode: The action mode (dev, release, or action)
+//   - version: The version string to use for release/action mode
 //   - actionTag: Optional override tag/SHA (takes precedence over version when in release mode)
 //   - resolver: Optional ActionSHAResolver for dynamic SHA resolution (can be nil for standalone use)
 //
@@ -28,7 +31,9 @@ const (
 //   - For dev mode: "./actions/setup" (local path)
 //   - For release mode with resolver: "github/gh-aw/actions/setup@<sha> # <version>" (SHA-pinned)
 //   - For release mode without resolver: "github/gh-aw/actions/setup@<version>" (tag-based, SHA resolved later)
-//   - Falls back to local path if version is invalid in release mode
+//   - For action mode with resolver: "github/gh-aw-actions/setup@<sha> # <version>" (SHA-pinned)
+//   - For action mode without resolver: "github/gh-aw-actions/setup@<version>" (tag-based, SHA resolved later)
+//   - Falls back to local path if version is invalid in release/action mode
 func ResolveSetupActionReference(actionMode ActionMode, version string, actionTag string, resolver ActionSHAResolver) string {
 	localPath := "./actions/setup"
 
@@ -38,6 +43,42 @@ func ResolveSetupActionReference(actionMode ActionMode, version string, actionTa
 		return localPath
 	}
 
+	// Action mode - use external gh-aw-actions repository with SHA pinning if possible
+	if actionMode == ActionModeAction {
+		// Use actionTag if provided, otherwise fall back to version
+		tag := actionTag
+		if tag == "" {
+			tag = version
+		}
+
+		// Check if tag is valid for action mode
+		if tag == "" || tag == "dev" {
+			actionRefLog.Print("WARNING: No release tag available in binary version (version is 'dev' or empty), falling back to local path")
+			return localPath
+		}
+
+		// Construct the remote reference: github/gh-aw-actions/setup@tag
+		actionRepo := GitHubActionsOrgRepo + "/setup"
+		remoteRef := fmt.Sprintf("%s@%s", actionRepo, tag)
+
+		// If a resolver is available, try to resolve the SHA
+		if resolver != nil {
+			sha, err := resolver.ResolveSHA(actionRepo, tag)
+			if err == nil && sha != "" {
+				pinnedRef := formatActionReference(actionRepo, sha, tag)
+				actionRefLog.Printf("Action mode: resolved %s to SHA-pinned reference: %s", remoteRef, pinnedRef)
+				return pinnedRef
+			}
+			if err != nil {
+				actionRefLog.Printf("Failed to resolve SHA for %s@%s: %v", actionRepo, tag, err)
+			}
+		}
+
+		// If no resolver or SHA resolution failed, return tag-based reference
+		actionRefLog.Printf("Action mode: using tag-based external actions repo reference: %s (SHA will be resolved later)", remoteRef)
+		return remoteRef
+	}
+
 	// Release mode - convert to remote reference
 	if actionMode == ActionModeRelease {
 		actionPath := strings.TrimPrefix(localPath, "./")
@@ -83,10 +124,11 @@ func ResolveSetupActionReference(actionMode ActionMode, version string, actionTa
 }
 
 // resolveActionReference converts a local action path to the appropriate reference
-// based on the current action mode (dev vs release).
+// based on the current action mode (dev vs release vs action).
 // If action-tag is specified in features, it overrides the mode check and enables release mode behavior.
 // For dev mode: returns the local path as-is (e.g., "./actions/create-issue")
 // For release mode: converts to SHA-pinned remote reference (e.g., "github/gh-aw/actions/create-issue@SHA # tag")
+// For action mode: converts to SHA-pinned reference in external repo if possible (e.g., "github/gh-aw-actions/create-issue@SHA # version")
 func (c *Compiler) resolveActionReference(localActionPath string, data *WorkflowData) string {
 	// Check if action-tag is specified in features - if so, override mode and use release behavior
 	hasActionTag := false
@@ -114,6 +156,11 @@ func (c *Compiler) resolveActionReference(localActionPath string, data *Workflow
 		}
 	}
 
+	// Action mode - use external gh-aw-actions repository with version tag (no SHA pinning)
+	if c.actionMode == ActionModeAction && !hasActionTag {
+		return c.convertToExternalActionsRef(localActionPath, data)
+	}
+
 	// Use release mode if either actionMode is release OR action-tag is specified
 	if c.actionMode == ActionModeRelease || hasActionTag {
 		// Convert to tag-based remote reference for release
@@ -214,3 +261,57 @@ func (c *Compiler) convertToRemoteActionRef(localPath string, data *WorkflowData
 
 	return remoteRef
 }
+
+// convertToExternalActionsRef converts a local action path to a SHA-pinned (if possible) reference
+// in the external github/gh-aw-actions repository.
+// Example: "./actions/create-issue" -> "github/gh-aw-actions/create-issue@<sha> # v1.0.0"
+//
+// If SHA resolution fails (no resolver or pin not available), falls back to version-tagged reference:
+// Example: "./actions/create-issue" -> "github/gh-aw-actions/create-issue@v1.0.0"
+func (c *Compiler) convertToExternalActionsRef(localPath string, data *WorkflowData) string {
+	// Strip the leading "./" prefix
+	actionPath := strings.TrimPrefix(localPath, "./")
+
+	// Strip the "actions/" prefix to get just the action name
+	// e.g., "actions/create-issue" -> "create-issue"
+	actionName := strings.TrimPrefix(actionPath, "actions/")
+
+	// Determine tag: use compiler actionTag or version
+	tag := c.actionTag
+	if tag == "" {
+		if data != nil && data.Features != nil {
+			if actionTagVal, exists := data.Features["action-tag"]; exists {
+				if actionTagStr, ok := actionTagVal.(string); ok && actionTagStr != "" {
+					tag = actionTagStr
+				}
+			}
+		}
+	}
+	if tag == "" {
+		tag = c.version
+		if tag == "" || tag == "dev" {
+			actionRefLog.Print("WARNING: No release tag available in binary version (version is 'dev' or empty)")
+			return ""
+		}
+	}
+
+	// Construct the external actions reference: github/gh-aw-actions/action-name@tag
+	actionRepo := fmt.Sprintf("%s/%s", GitHubActionsOrgRepo, actionName)
+	remoteRef := fmt.Sprintf("%s@%s", actionRepo, tag)
+
+	// Try to resolve the SHA using action pins
+	if data != nil {
+		pinnedRef, err := GetActionPinWithData(actionRepo, tag, data)
+		if err != nil {
+			// Log and fall through to tag-based reference (action mode is not strict)
+			actionRefLog.Printf("Failed to pin action %s@%s: %v, falling back to tag-based reference", actionRepo, tag, err)
+		} else if pinnedRef != "" {
+			actionRefLog.Printf("Action mode: resolved %s to SHA-pinned reference: %s", remoteRef, pinnedRef)
+			return pinnedRef
+		}
+	}
+
+	// If SHA resolution unavailable or pin not found, return tag-based reference
+	actionRefLog.Printf("Action mode: using tag-based external actions repo reference: %s (SHA will be resolved later)", remoteRef)
+	return remoteRef
+}
diff --git a/pkg/workflow/compiler_custom_actions_test.go b/pkg/workflow/compiler_custom_actions_test.go
index 5b7bd932c8b..e2de221cd84 100644
--- a/pkg/workflow/compiler_custom_actions_test.go
+++ b/pkg/workflow/compiler_custom_actions_test.go
@@ -19,6 +19,7 @@ func TestActionModeValidation(t *testing.T) {
 		{ActionModeDev, true},
 		{ActionModeRelease, true},
 		{ActionModeScript, true},
+		{ActionModeAction, true},
 		{ActionMode("invalid"), false},
 		{ActionMode(""), false},
 	}
@@ -41,6 +42,7 @@ func TestActionModeString(t *testing.T) {
 		{ActionModeDev, "dev"},
 		{ActionModeRelease, "release"},
 		{ActionModeScript, "script"},
+		{ActionModeAction, "action"},
 	}
 
 	for _, tt := range tests {
@@ -78,6 +80,11 @@ func TestCompilerSetActionMode(t *testing.T) {
 	if compiler.GetActionMode() != ActionModeScript {
 		t.Errorf("Expected action mode script, got %s", compiler.GetActionMode())
 	}
+
+	compiler.SetActionMode(ActionModeAction)
+	if compiler.GetActionMode() != ActionModeAction {
+		t.Errorf("Expected action mode action, got %s", compiler.GetActionMode())
+	}
 }
 
 // TestActionModeIsScript tests the IsScript() method
@@ -89,6 +96,7 @@ func TestActionModeIsScript(t *testing.T) {
 		{ActionModeDev, false},
 		{ActionModeRelease, false},
 		{ActionModeScript, true},
+		{ActionModeAction, false},
 	}
 
 	for _, tt := range tests {
@@ -100,6 +108,27 @@ func TestActionModeIsScript(t *testing.T) {
 	}
 }
 
+// TestActionModeIsAction tests the IsAction() method
+func TestActionModeIsAction(t *testing.T) {
+	tests := []struct {
+		mode     ActionMode
+		isAction bool
+	}{
+		{ActionModeDev, false},
+		{ActionModeRelease, false},
+		{ActionModeScript, false},
+		{ActionModeAction, true},
+	}
+
+	for _, tt := range tests {
+		t.Run(string(tt.mode), func(t *testing.T) {
+			if got := tt.mode.IsAction(); got != tt.isAction {
+				t.Errorf("ActionMode(%q).IsAction() = %v, want %v", tt.mode, got, tt.isAction)
+			}
+		})
+	}
+}
+
 // TestInlineActionModeCompilation tests workflow compilation with inline mode (default)
 func TestInlineActionModeCompilation(t *testing.T) {
 	// Create a temporary directory for the test
@@ -331,3 +360,115 @@ func TestCheckoutActionsFolderDevModeAlwaysEmitsCheckout(t *testing.T) {
 		})
 	}
 }
+
+// TestResolveSetupActionReferenceActionMode tests that action mode resolves to the external gh-aw-actions repo
+func TestResolveSetupActionReferenceActionMode(t *testing.T) {
+	ref := ResolveSetupActionReference(ActionModeAction, "v1.2.3", "", nil)
+	if ref != "github/gh-aw-actions/setup@v1.2.3" {
+		t.Errorf("Action mode should resolve to 'github/gh-aw-actions/setup@v1.2.3', got %q", ref)
+	}
+}
+
+// TestResolveSetupActionReferenceActionModeWithTag tests action mode with an explicit action tag
+func TestResolveSetupActionReferenceActionModeWithTag(t *testing.T) {
+	ref := ResolveSetupActionReference(ActionModeAction, "v1.0.0", "v2.0.0", nil)
+	if ref != "github/gh-aw-actions/setup@v2.0.0" {
+		t.Errorf("Action mode with tag should resolve to 'github/gh-aw-actions/setup@v2.0.0', got %q", ref)
+	}
+}
+
+// TestResolveSetupActionReferenceActionModeDevVersion tests action mode falls back to local path for dev version
+func TestResolveSetupActionReferenceActionModeDevVersion(t *testing.T) {
+	ref := ResolveSetupActionReference(ActionModeAction, "dev", "", nil)
+	if ref != "./actions/setup" {
+		t.Errorf("Action mode with dev version should fall back to './actions/setup', got %q", ref)
+	}
+}
+
+// TestCheckoutActionsFolderActionModeNoCheckout verifies that action mode does not generate a checkout step
+func TestCheckoutActionsFolderActionModeNoCheckout(t *testing.T) {
+	compiler := NewCompilerWithVersion("v1.2.3")
+	compiler.SetActionMode(ActionModeAction)
+
+	lines := compiler.generateCheckoutActionsFolder(nil)
+	if len(lines) > 0 {
+		t.Error("Action mode should not generate a checkout step for actions folder")
+	}
+}
+
+// TestActionModeCompilation tests workflow compilation with action mode
+func TestActionModeCompilation(t *testing.T) {
+	tempDir := t.TempDir()
+
+	workflowContent := `---
+name: Test Action Mode
+on: issues
+safe-outputs:
+  create-issue:
+    max: 1
+---
+
+Test workflow with action mode.
+`
+
+	workflowPath := tempDir + "/test-workflow.md"
+	if err := os.WriteFile(workflowPath, []byte(workflowContent), 0644); err != nil {
+		t.Fatalf("Failed to write test workflow: %v", err)
+	}
+
+	compiler := NewCompilerWithVersion("v1.2.3")
+	compiler.SetActionMode(ActionModeAction)
+	compiler.SetNoEmit(false)
+
+	if err := compiler.CompileWorkflow(workflowPath); err != nil {
+		t.Fatalf("Compilation failed: %v", err)
+	}
+
+	lockPath := stringutil.MarkdownToLockFile(workflowPath)
+	lockContent, err := os.ReadFile(lockPath)
+	if err != nil {
+		t.Fatalf("Failed to read lock file: %v", err)
+	}
+
+	lockStr := string(lockContent)
+
+	// Verify it uses the external gh-aw-actions/setup action
+	if !strings.Contains(lockStr, "github/gh-aw-actions/setup@v1.2.3") {
+		t.Errorf("Action mode should use 'github/gh-aw-actions/setup@v1.2.3', lock file:\n%s", lockStr)
+	}
+
+	// Verify it does NOT use the internal gh-aw/actions/setup path
+	if strings.Contains(lockStr, "github/gh-aw/actions/setup@") {
+		t.Error("Action mode should NOT use 'github/gh-aw/actions/setup@', use external repo instead")
+	}
+
+	// Verify no local checkout step for actions folder
+	if strings.Contains(lockStr, "Checkout actions folder") {
+		t.Error("Action mode should NOT include a 'Checkout actions folder' step")
+	}
+}
+
+// TestResolveSetupActionReferenceActionModeWithResolver tests that action mode uses SHA resolver when available
+func TestResolveSetupActionReferenceActionModeWithResolver(t *testing.T) {
+	t.Run("action mode with resolver attempts SHA resolution", func(t *testing.T) {
+		// Create mock action resolver and cache
+		cache := NewActionCache("")
+		resolver := NewActionResolver(cache)
+
+		// The resolver will fail to resolve github/gh-aw-actions/setup@v1.0.0
+		// since it's not a real tag, but it should fall back gracefully to tag-based reference
+		ref := ResolveSetupActionReference(ActionModeAction, "v1.0.0", "", resolver)
+
+		// Without a valid pin or successful resolution, should return tag-based reference
+		if ref != "github/gh-aw-actions/setup@v1.0.0" {
+			t.Errorf("expected 'github/gh-aw-actions/setup@v1.0.0', got %q", ref)
+		}
+	})
+
+	t.Run("action mode with nil resolver returns tag-based reference", func(t *testing.T) {
+		ref := ResolveSetupActionReference(ActionModeAction, "v1.0.0", "", nil)
+		if ref != "github/gh-aw-actions/setup@v1.0.0" {
+			t.Errorf("expected 'github/gh-aw-actions/setup@v1.0.0', got %q", ref)
+		}
+	})
+}
diff --git a/pkg/workflow/maintenance_workflow.go b/pkg/workflow/maintenance_workflow.go
index f3855862a4a..51515289cf1 100644
--- a/pkg/workflow/maintenance_workflow.go
+++ b/pkg/workflow/maintenance_workflow.go
@@ -15,6 +15,7 @@ var maintenanceLog = logger.New("workflow:maintenance_workflow")
 // generateInstallCLISteps generates YAML steps to install or build the gh-aw CLI.
 // In dev mode: builds from source using Setup Go + Build gh-aw (./gh-aw binary available)
 // In release mode: installs the released CLI via the setup-cli action (gh aw available)
+// In action mode: installs the released CLI via the gh-aw-actions/setup-cli action (gh aw available)
 func generateInstallCLISteps(actionMode ActionMode, version string, actionTag string) string {
 	if actionMode == ActionModeDev {
 		return `      - name: Setup Go
@@ -29,11 +30,22 @@ func generateInstallCLISteps(actionMode ActionMode, version string, actionTag st
 `
 	}
 
-	// Release mode: use setup-cli action (consistent with copilot-setup-steps.yml)
 	cliTag := actionTag
 	if cliTag == "" {
 		cliTag = version
 	}
+
+	// Action mode: use setup-cli action from external gh-aw-actions repository
+	if actionMode == ActionModeAction {
+		return `      - name: Install gh-aw
+        uses: github/gh-aw-actions/setup-cli@` + cliTag + `
+        with:
+          version: ` + cliTag + `
+
+`
+	}
+
+	// Release mode: use setup-cli action (consistent with copilot-setup-steps.yml)
 	return `      - name: Install gh-aw
         uses: github/gh-aw/actions/setup-cli@` + cliTag + `
         with:
