diff --git a/cmd/gh-aw/main.go b/cmd/gh-aw/main.go
index 2376a6f41db..308c5bedc55 100644
--- a/cmd/gh-aw/main.go
+++ b/cmd/gh-aw/main.go
@@ -697,9 +697,6 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all
 	// Create and setup add-wizard command
 	addWizardCmd := cli.NewAddWizardCommand(validateEngine)
 
-	// Create and setup bootstrap command
-	bootstrapCmd := cli.NewBootstrapCommand(validateEngine)
-
 	// Create and setup update command
 	updateCmd := cli.NewUpdateCommand(validateEngine)
 
@@ -842,7 +839,6 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all
 	newCmd.GroupID = "setup"
 	addCmd.GroupID = "setup"
 	addWizardCmd.GroupID = "setup"
-	bootstrapCmd.GroupID = "setup"
 	removeCmd.GroupID = "setup"
 	updateCmd.GroupID = "setup"
 	deployCmd.GroupID = "setup"
@@ -889,7 +885,6 @@ Use "` + string(constants.CLIExtensionPrefix) + ` help all" to show help for all
 	// Add all commands to root
 	rootCmd.AddCommand(addCmd)
 	rootCmd.AddCommand(addWizardCmd)
-	rootCmd.AddCommand(bootstrapCmd)
 	rootCmd.AddCommand(updateCmd)
 	rootCmd.AddCommand(deployCmd)
 	rootCmd.AddCommand(upgradeCmd)
diff --git a/pkg/cli/add_command.go b/pkg/cli/add_command.go
index 2b3807351d5..5cf869be24c 100644
--- a/pkg/cli/add_command.go
+++ b/pkg/cli/add_command.go
@@ -156,15 +156,31 @@ func runAddCommand(cmd *cobra.Command, args []string, validateEngine func(string
 	if err != nil {
 		return err
 	}
-	if _, err := AddResolvedWorkflows(cmd.Context(), args, resolved, opts); err != nil {
+	if err := rejectBootstrapProfileForRegularAdd(args, resolved.BootstrapProfile); err != nil {
+		return err
+	}
+	if err := ensureAddRepositoryInitialized(engineOverride, verbose); err != nil {
 		return err
 	}
-	if resolved.BootstrapProfile != nil {
-		printBootstrapConfigTODO(cmd.ErrOrStderr(), resolved.BootstrapProfile)
+	if _, err := AddResolvedWorkflows(cmd.Context(), args, resolved, opts); err != nil {
+		return err
 	}
 	return nil
 }
 
+func rejectBootstrapProfileForRegularAdd(sources []string, profile *resolvedBootstrapProfile) error {
+	if profile == nil || profile.Profile == nil || len(profile.Profile.Config) == 0 {
+		return nil
+	}
+
+	requestedSources := strings.Join(sources, " ")
+	if requestedSources == "" {
+		requestedSources = profile.PackageID
+	}
+
+	return fmt.Errorf("package %s declares aw.yml config and cannot be installed with 'gh aw add'. Use 'gh aw add-wizard %s' so the config steps can run interactively", profile.PackageID, requestedSources)
+}
+
 func registerAddCommandFlags(cmd *cobra.Command) {
 	// Add name flag to add command
 	cmd.Flags().StringP("name", "n", "", "Specify name for the added workflow (without .md extension)")
@@ -390,7 +406,11 @@ func addWorkflowWithTracking(ctx context.Context, resolved *ResolvedWorkflow, tr
 	if resolved.IsPackageAgentFile {
 		return addAgentFileWithTracking(resolved, tracker, opts, gitRoot)
 	}
-	skip, err := validateWorkflowDestination(githubWorkflowsDir, workflowName, opts)
+	sourceRepo := ""
+	if sourceInfo != nil && !sourceInfo.IsLocal {
+		sourceRepo = workflowSpec.RepoSlug
+	}
+	skip, err := validateWorkflowDestination(githubWorkflowsDir, workflowName, sourceRepo, opts)
 	if err != nil {
 		return err
 	}
@@ -430,11 +450,18 @@ func reportAddWorkflowStart(workflowSpec *WorkflowSpec, sourceContent []byte, op
 	fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Using pre-fetched workflow content (%d bytes)", len(sourceContent))))
 }
 
-func validateWorkflowDestination(githubWorkflowsDir, workflowName string, opts AddOptions) (bool, error) {
+func validateWorkflowDestination(githubWorkflowsDir, workflowName, sourceRepo string, opts AddOptions) (bool, error) {
 	existingFile := filepath.Join(githubWorkflowsDir, workflowName+".md")
 	if !fileutil.FileExists(existingFile) || opts.Force {
 		return false, nil
 	}
+	if sourceRepo != "" {
+		existingSourceRepo := readSourceRepoFromFile(existingFile)
+		if existingSourceRepo == sourceRepo {
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Workflow from same source already exists, skipping: "+existingFile))
+			return true, nil
+		}
+	}
 	if opts.FromWildcard {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Workflow '%s' already exists in .github/workflows/. Skipping.", workflowName)))
 		return true, nil
diff --git a/pkg/cli/add_command_test.go b/pkg/cli/add_command_test.go
index 0427be04654..66ec9493f60 100644
--- a/pkg/cli/add_command_test.go
+++ b/pkg/cli/add_command_test.go
@@ -10,6 +10,7 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/github/gh-aw/pkg/gitutil"
 	"github.com/github/gh-aw/pkg/testutil"
 	"github.com/github/gh-aw/pkg/workflow"
 	"github.com/spf13/cobra"
@@ -367,6 +368,198 @@ func TestAddCommandArgs(t *testing.T) {
 	require.NoError(t, err, "Should not error with multiple arguments")
 }
 
+func TestRejectBootstrapProfileForRegularAdd(t *testing.T) {
+	profileWithConfig := &resolvedBootstrapProfile{
+		PackageID: "githubnext/central-agentic-ops",
+		Profile: &repositoryPackageBootstrap{
+			Config: []repositoryPackageBootstrapAction{
+				{Type: "repo-variable", Name: "EXAMPLE", Prompt: "Enter value"},
+			},
+		},
+	}
+
+	t.Run("rejects regular add for packages with manifest config", func(t *testing.T) {
+		err := rejectBootstrapProfileForRegularAdd([]string{"githubnext/central-agentic-ops"}, profileWithConfig)
+		require.Error(t, err)
+		assert.Contains(t, err.Error(), "package githubnext/central-agentic-ops declares aw.yml config")
+		assert.Contains(t, err.Error(), "gh aw add-wizard githubnext/central-agentic-ops")
+	})
+
+	t.Run("uses requested sources in the add-wizard guidance", func(t *testing.T) {
+		err := rejectBootstrapProfileForRegularAdd([]string{"githubnext/central-agentic-ops", "./local-workflow.md"}, profileWithConfig)
+		require.Error(t, err)
+		assert.Contains(t, err.Error(), "gh aw add-wizard githubnext/central-agentic-ops ./local-workflow.md")
+	})
+
+	t.Run("allows packages without manifest config", func(t *testing.T) {
+		err := rejectBootstrapProfileForRegularAdd([]string{"owner/pkg"}, nil)
+		require.NoError(t, err)
+
+		err = rejectBootstrapProfileForRegularAdd([]string{"owner/pkg"}, &resolvedBootstrapProfile{
+			PackageID: "owner/pkg",
+			Profile:   &repositoryPackageBootstrap{Config: nil},
+		})
+		require.NoError(t, err)
+	})
+}
+
+func TestEnsureAddRepositoryInitialized(t *testing.T) {
+	originalFindGitRoot := addFindGitRoot
+	originalInitRepository := addInitRepository
+	originalMissingInitMarkers := addMissingInitMarkers
+	t.Cleanup(func() {
+		addFindGitRoot = originalFindGitRoot
+		addInitRepository = originalInitRepository
+		addMissingInitMarkers = originalMissingInitMarkers
+	})
+
+	t.Run("skips initialization outside a git checkout", func(t *testing.T) {
+		addFindGitRoot = func() (string, error) { return "", gitutil.ErrNotGitRepository }
+		addMissingInitMarkers = func(string, string) ([]string, error) {
+			t.Fatal("missing init markers check should be skipped outside a git checkout")
+			return nil, nil
+		}
+		addInitRepository = func(InitOptions) error {
+			t.Fatal("InitRepository should not run outside a git checkout")
+			return nil
+		}
+
+		err := ensureAddRepositoryInitialized("", false)
+		require.NoError(t, err)
+	})
+
+	t.Run("runs init when required markers are missing", func(t *testing.T) {
+		repoDir := t.TempDir()
+		addFindGitRoot = func() (string, error) { return repoDir, nil }
+		addMissingInitMarkers = func(baseDir string, engineOverride string) ([]string, error) {
+			assert.Equal(t, ".", baseDir)
+			assert.Equal(t, "claude", engineOverride)
+			return []string{".gitattributes"}, nil
+		}
+
+		called := false
+		addInitRepository = func(opts InitOptions) error {
+			called = true
+			assert.True(t, opts.Verbose)
+			assert.Equal(t, "claude", opts.Engine)
+			assert.True(t, opts.Skill)
+			assert.True(t, opts.Agent)
+			assert.True(t, opts.MCP)
+			assert.False(t, opts.CodespaceEnabled)
+			assert.False(t, opts.Completions)
+			assert.False(t, opts.CreatePR)
+			return nil
+		}
+
+		err := ensureAddRepositoryInitialized("claude", true)
+		require.NoError(t, err)
+		assert.True(t, called)
+	})
+
+	t.Run("does nothing when markers are already present", func(t *testing.T) {
+		repoDir := t.TempDir()
+		addFindGitRoot = func() (string, error) { return repoDir, nil }
+		addMissingInitMarkers = func(string, string) ([]string, error) { return nil, nil }
+		addInitRepository = func(InitOptions) error {
+			t.Fatal("InitRepository should not run when markers are already present")
+			return nil
+		}
+
+		err := ensureAddRepositoryInitialized("", false)
+		require.NoError(t, err)
+	})
+}
+
+func TestAddResolvedWorkflows_IgnoresBootstrapRequireOwnerTypeDuringInstall(t *testing.T) {
+	originalCheckOwnerType := bootstrapCheckOwnerType
+	t.Cleanup(func() {
+		bootstrapCheckOwnerType = originalCheckOwnerType
+	})
+
+	bootstrapCheckOwnerType = func(context.Context, string) (string, error) { return "User", nil }
+
+	resolved := &ResolvedWorkflows{
+		Workflows: nil,
+		BootstrapProfile: &resolvedBootstrapProfile{
+			PackageID: "githubnext/central-agentic-ops",
+			Profile: &repositoryPackageBootstrap{
+				Config: []repositoryPackageBootstrapAction{{Type: "require-owner-type", Value: "org"}},
+			},
+		},
+	}
+
+	_, err := AddResolvedWorkflows(context.Background(), []string{"githubnext/central-agentic-ops"}, resolved, AddOptions{NoGitattributes: true})
+	require.NoError(t, err)
+}
+
+func TestCompileDispatchWorkflowDependencies_FallsBackToRawFrontmatter(t *testing.T) {
+	tmpDir := testutil.TempDir(t, "dispatch-workflow-fallback-*")
+	workflowsDir := setupMinimalGitRepo(t, tmpDir)
+
+	mainPath := filepath.Join(workflowsDir, "dispatcher.md")
+	workerPath := filepath.Join(workflowsDir, "worker.md")
+
+	require.NoError(t, os.WriteFile(mainPath, []byte(`---
+name: Dispatcher
+on:
+  workflow_dispatch:
+safe-outputs:
+  dispatch-workflow:
+    workflows: [worker]
+imports:
+  - uses: shared/missing.md
+---
+
+# Dispatcher
+`), 0o644))
+	require.NoError(t, os.WriteFile(workerPath, []byte(`---
+name: Worker
+on:
+  workflow_dispatch:
+---
+
+# Worker
+`), 0o644))
+
+	compileDispatchWorkflowDependencies(context.Background(), mainPath, false, true, "", nil)
+
+	lockPath := filepath.Join(workflowsDir, "worker.lock.yml")
+	_, err := os.Stat(lockPath)
+	require.NoError(t, err, "dispatch dependency should still be compiled when merged parse fails")
+	lockContent, err := os.ReadFile(lockPath)
+	require.NoError(t, err)
+	assert.Contains(t, string(lockContent), "name: \"Worker\"", "compiled dispatch dependency should preserve its workflow name")
+}
+
+func TestValidateWorkflowDestination_SkipsExistingWorkflowFromSameSource(t *testing.T) {
+	workflowsDir := t.TempDir()
+	existingPath := filepath.Join(workflowsDir, "dependabot.md")
+	require.NoError(t, os.WriteFile(existingPath, []byte(`---
+source: githubnext/central-agentic-ops/.github/workflows/dependabot.md@main
+---
+# Dependabot
+`), 0o644))
+
+	skip, err := validateWorkflowDestination(workflowsDir, "dependabot", "githubnext/central-agentic-ops", AddOptions{})
+	require.NoError(t, err)
+	assert.True(t, skip)
+}
+
+func TestValidateWorkflowDestination_ErrorsForExistingWorkflowFromDifferentSource(t *testing.T) {
+	workflowsDir := t.TempDir()
+	existingPath := filepath.Join(workflowsDir, "dependabot.md")
+	require.NoError(t, os.WriteFile(existingPath, []byte(`---
+source: octo/other/.github/workflows/dependabot.md@main
+---
+# Dependabot
+`), 0o644))
+
+	skip, err := validateWorkflowDestination(workflowsDir, "dependabot", "githubnext/central-agentic-ops", AddOptions{})
+	require.Error(t, err)
+	assert.False(t, skip)
+	assert.Contains(t, err.Error(), "workflow 'dependabot' already exists")
+}
+
 // TestAddMultipleWorkflowsNameFlag verifies that --name is not allowed when multiple workflows are specified.
 func TestAddMultipleWorkflowsNameFlag(t *testing.T) {
 	cmd := NewAddCommand(validateEngineStub)
diff --git a/pkg/cli/add_init.go b/pkg/cli/add_init.go
new file mode 100644
index 00000000000..0ddc73dfb71
--- /dev/null
+++ b/pkg/cli/add_init.go
@@ -0,0 +1,62 @@
+package cli
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/github/gh-aw/pkg/gitutil"
+)
+
+var addFindGitRoot = gitutil.FindGitRoot
+var addInitRepository = InitRepository
+var addMissingInitMarkers = missingBootstrapInitMarkers
+
+func ensureAddRepositoryInitialized(engineOverride string, verbose bool) error {
+	_, err := ensureAddRepositoryInitializedWithDetails(engineOverride, verbose)
+	return err
+}
+
+func ensureAddRepositoryInitializedWithDetails(engineOverride string, verbose bool) ([]string, error) {
+	gitRoot, err := addFindGitRoot()
+	if err != nil {
+		if errors.Is(err, gitutil.ErrNotGitRepository) {
+			addLog.Print("Skipping automatic repository initialization outside a git checkout")
+			return nil, nil
+		}
+		return nil, fmt.Errorf("failed to determine repository root for automatic initialization: %w", err)
+	}
+
+	var initializedFiles []string
+	err = withWorkingDir(gitRoot, func() error {
+		missingMarkers, err := addMissingInitMarkers(".", engineOverride)
+		if err != nil {
+			return fmt.Errorf("failed to inspect repository initialization state: %w", err)
+		}
+		if len(missingMarkers) == 0 {
+			return nil
+		}
+		initializedFiles = append(initializedFiles, missingMarkers...)
+
+		addLog.Printf("Repository missing init markers; running init: %v", missingMarkers)
+		if err := addInitRepository(InitOptions{
+			Verbose:          verbose,
+			Engine:           engineOverride,
+			Skill:            true,
+			Agent:            true,
+			MCP:              true,
+			CodespaceRepos:   []string{},
+			CodespaceEnabled: false,
+			Completions:      false,
+			CreatePR:         false,
+		}); err != nil {
+			return fmt.Errorf("failed to initialize repository for agentic workflows: %w", err)
+		}
+
+		return nil
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return initializedFiles, nil
+}
diff --git a/pkg/cli/add_interactive_orchestrator.go b/pkg/cli/add_interactive_orchestrator.go
index faf6604b2a9..c25de4414dd 100644
--- a/pkg/cli/add_interactive_orchestrator.go
+++ b/pkg/cli/add_interactive_orchestrator.go
@@ -135,8 +135,13 @@ func RunAddInteractive(ctx context.Context, config *AddInteractiveConfig) error
 		return err
 	}
 
+	initFiles, err := ensureAddRepositoryInitializedWithDetails(config.EngineOverride, config.Verbose)
+	if err != nil {
+		return err
+	}
+
 	// Step 7: Determine files to add
-	filesToAdd, initFiles, err := config.determineFilesToAdd()
+	filesToAdd, _, err := config.determineFilesToAdd()
 	if err != nil {
 		return err
 	}
@@ -311,6 +316,13 @@ func (c *AddInteractiveConfig) confirmChanges(workflowFiles, initFiles []string,
 	addInteractiveLog.Print("Confirming changes with user")
 
 	fmt.Fprintln(os.Stderr, "")
+	if len(initFiles) > 0 {
+		fmt.Fprintln(os.Stderr, "The repository will also be initialized with:")
+		for _, f := range initFiles {
+			fmt.Fprintf(os.Stderr, "  • %s\n", f)
+		}
+		fmt.Fprintln(os.Stderr, "")
+	}
 
 	confirmed := true // Default to yes
 	form := console.NewConfirmForm(
diff --git a/pkg/cli/add_package_manifest_test.go b/pkg/cli/add_package_manifest_test.go
index 54a7d776462..ef82ee215dd 100644
--- a/pkg/cli/add_package_manifest_test.go
+++ b/pkg/cli/add_package_manifest_test.go
@@ -2212,6 +2212,7 @@ func TestPrintBootstrapConfigTODO(t *testing.T) {
 					{Type: "repo-variable", Name: "MY_VAR", Prompt: "Enter a value"},
 					{Type: "repo-secret", Name: "MY_SECRET", Prompt: "Enter secret"},
 					{Type: "copilot-auth", Secret: "COPILOT_TOKEN"},
+					{Type: "commit-and-push", Message: "Bootstrap repository changes"},
 					{Type: "handoff", Message: "Run the bootstrap wizard."},
 				},
 			},
@@ -2224,6 +2225,8 @@ func TestPrintBootstrapConfigTODO(t *testing.T) {
 		assert.Contains(t, out, "☐ Set repository variable: MY_VAR")
 		assert.Contains(t, out, "☐ Set repository secret: MY_SECRET")
 		assert.Contains(t, out, "☐ Set Copilot PAT secret: COPILOT_TOKEN")
+		assert.Contains(t, out, "☐ Commit and push local changes — Bootstrap repository changes")
 		assert.Contains(t, out, "Run the bootstrap wizard.")
+		assert.NotContains(t, out, "gh aw bootstrap")
 	})
 }
diff --git a/pkg/cli/add_workflow_compilation.go b/pkg/cli/add_workflow_compilation.go
index 6fdcca8d191..c6fe2086e92 100644
--- a/pkg/cli/add_workflow_compilation.go
+++ b/pkg/cli/add_workflow_compilation.go
@@ -2,14 +2,17 @@ package cli
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 
 	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/fileutil"
 	"github.com/github/gh-aw/pkg/gitutil"
 	"github.com/github/gh-aw/pkg/logger"
+	"github.com/github/gh-aw/pkg/parser"
 	"github.com/github/gh-aw/pkg/stringutil"
 	"github.com/github/gh-aw/pkg/workflow"
 )
@@ -127,16 +130,14 @@ func compileWorkflowWithTrackingAndRefresh(ctx context.Context, filePath string,
 // called before compiling the main workflow, because the dispatch-workflow validator
 // requires every referenced .md workflow to have an up-to-date .lock.yml.
 func compileDispatchWorkflowDependencies(ctx context.Context, workflowFile string, verbose, quiet bool, engineOverride string, tracker *FileTracker) {
-	// Parse the merged safe-outputs to get the canonical list of dispatch-workflow names.
-	compiler := workflow.NewCompiler()
-	data, err := compiler.ParseWorkflowFile(workflowFile)
-	if err != nil || data == nil || data.SafeOutputs == nil || data.SafeOutputs.DispatchWorkflow == nil {
+	workflowNames := dispatchWorkflowNamesForCompilation(workflowFile)
+	if len(workflowNames) == 0 {
 		return
 	}
 
 	workflowsDir := filepath.Dir(workflowFile)
 
-	for _, name := range data.SafeOutputs.DispatchWorkflow.Workflows {
+	for _, name := range workflowNames {
 		mdPath := filepath.Join(workflowsDir, name+".md")
 		lockPath := stringutil.MarkdownToLockFile(mdPath)
 
@@ -168,6 +169,92 @@ func compileDispatchWorkflowDependencies(ctx context.Context, workflowFile strin
 	}
 }
 
+func dispatchWorkflowNamesForCompilation(workflowFile string) []string {
+	compiler := workflow.NewCompiler()
+	data, err := compiler.ParseWorkflowFile(workflowFile)
+	if err == nil && data != nil && data.SafeOutputs != nil && data.SafeOutputs.DispatchWorkflow != nil {
+		if names := dedupeDispatchWorkflowNames(data.SafeOutputs.DispatchWorkflow.Workflows); len(names) > 0 {
+			return names
+		}
+	}
+
+	if err != nil {
+		var sharedErr *workflow.SharedWorkflowError
+		var redirectErr *workflow.RedirectOnlyWorkflowError
+		if !errors.As(err, &sharedErr) && !errors.As(err, &redirectErr) {
+			addWorkflowCompilationLog.Printf("Falling back to raw dispatch-workflow extraction for %s after parse error: %v", workflowFile, err)
+		}
+	}
+
+	return extractDispatchWorkflowNamesFromFrontmatter(workflowFile)
+}
+
+func extractDispatchWorkflowNamesFromFrontmatter(workflowFile string) []string {
+	content, err := os.ReadFile(workflowFile)
+	if err != nil {
+		return nil
+	}
+
+	frontmatter, err := parser.ExtractFrontmatterFromContent(string(content))
+	if err != nil || frontmatter == nil {
+		return nil
+	}
+
+	safeOutputs, ok := frontmatter.Frontmatter["safe-outputs"].(map[string]any)
+	if !ok {
+		return nil
+	}
+
+	dispatchConfig, exists := safeOutputs["dispatch-workflow"]
+	if !exists {
+		return nil
+	}
+
+	var names []string
+	switch config := dispatchConfig.(type) {
+	case []any:
+		names = appendDispatchWorkflowNames(names, config)
+	case map[string]any:
+		if workflows, ok := config["workflows"].([]any); ok {
+			names = appendDispatchWorkflowNames(names, workflows)
+		}
+	}
+
+	return dedupeDispatchWorkflowNames(names)
+}
+
+func appendDispatchWorkflowNames(names []string, raw []any) []string {
+	for _, candidate := range raw {
+		name, ok := candidate.(string)
+		if !ok {
+			continue
+		}
+		trimmed := strings.TrimSpace(name)
+		if trimmed == "" {
+			continue
+		}
+		names = append(names, trimmed)
+	}
+	return names
+}
+
+func dedupeDispatchWorkflowNames(names []string) []string {
+	seen := make(map[string]struct{}, len(names))
+	result := make([]string, 0, len(names))
+	for _, name := range names {
+		trimmed := strings.TrimSpace(name)
+		if trimmed == "" {
+			continue
+		}
+		if _, exists := seen[trimmed]; exists {
+			continue
+		}
+		seen[trimmed] = struct{}{}
+		result = append(result, trimmed)
+	}
+	return result
+}
+
 // This function preserves the existing frontmatter formatting while adding the source field.
 func addSourceToWorkflow(content, source string) (string, error) {
 	// Use shared frontmatter logic that preserves formatting
diff --git a/pkg/cli/bootstrap.go b/pkg/cli/bootstrap.go
deleted file mode 100644
index 809eb558cbd..00000000000
--- a/pkg/cli/bootstrap.go
+++ /dev/null
@@ -1,593 +0,0 @@
-package cli
-
-import (
-	"context"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"github.com/github/gh-aw/pkg/console"
-	"github.com/github/gh-aw/pkg/constants"
-	"github.com/github/gh-aw/pkg/logger"
-	"github.com/github/gh-aw/pkg/workflow"
-)
-
-var bootstrapLog = logger.New("cli:bootstrap")
-
-type BootstrapOptions struct {
-	Ctx              context.Context
-	Repo             string
-	Dir              string
-	CreateRepo       bool
-	Visibility       string
-	RequireOwnerType string
-	Yes              bool
-	PlanOnly         bool
-	EngineOverride   string
-	Sources          []string
-	Force            bool
-	NoCompile        bool
-	Verbose          bool
-}
-
-type bootstrapPlan struct {
-	Repo               string
-	Dir                string
-	RepoExists         bool
-	CreateRepo         bool
-	CloneRepo          bool
-	AttachedCheckout   bool
-	InitNeeded         bool
-	InitMissingMarkers []string
-	ResolvedSources    []string
-	SkippedSources     []string
-	CompileAfterAdd    bool
-	OwnerType          string
-	BootstrapProfile   *resolvedBootstrapProfile
-	ProfilePlanLines   []string
-	ProfileNeedsAction bool
-	NeedsMutation      bool
-	PlanLines          []string
-}
-
-type bootstrapRuntime struct {
-	setupRepositoryRuntime
-	confirmAction    func(string, string, string) (bool, error)
-	initRepo         func(InitOptions) error
-	addWorkflows     func(context.Context, []string, AddOptions) (*AddWorkflowsResult, error)
-	compileWorkflows func(context.Context, CompileConfig) ([]*workflow.WorkflowData, error)
-	resolveProfile   func(context.Context, []string) (*resolvedBootstrapProfile, error)
-	profileNeedsPlan func(context.Context, string, *resolvedBootstrapProfile, []string, bool) (bool, []string, error)
-	executeProfile   func(context.Context, bootstrapProfileRunConfig) error
-}
-
-const (
-	bootstrapAddWorkflowsRetryHint = "repository initialization completed; re-run bootstrap to retry workflow addition"
-	bootstrapMCPConfigPath         = ".github/mcp.json"
-	bootstrapCopilotSetupPath      = ".github/workflows/copilot-setup-steps.yml"
-	bootstrapAgenticSkillPath      = ".github/skills/agentic-workflows/SKILL.md"
-	bootstrapAgenticAgentPath      = ".github/agents/agentic-workflows.md"
-)
-
-func defaultBootstrapRuntime() bootstrapRuntime {
-	setupRuntime := defaultSetupRepositoryRuntime()
-	return bootstrapRuntime{
-		setupRepositoryRuntime: setupRuntime,
-		confirmAction:          console.ConfirmAction,
-		initRepo:               InitRepository,
-		addWorkflows:           AddWorkflows,
-		compileWorkflows:       CompileWorkflows,
-		resolveProfile:         resolveBootstrapProfileFromSources,
-		profileNeedsPlan:       buildBootstrapProfilePlan,
-		executeProfile:         executeBootstrapProfile,
-	}
-}
-
-func RunBootstrap(opts BootstrapOptions) error {
-	originalDir, err := os.Getwd()
-	if err != nil {
-		return fmt.Errorf("failed to determine current directory: %w", err)
-	}
-	return runBootstrapWithRuntime(normalizeBootstrapOptions(opts), defaultBootstrapRuntime(), originalDir)
-}
-
-func runBootstrapWithRuntime(opts BootstrapOptions, runtime bootstrapRuntime, originalDir string) error {
-	runtime = normalizeBootstrapRuntime(runtime)
-
-	if err := validateBootstrapOptions(opts); err != nil {
-		return err
-	}
-
-	ctx := opts.Ctx
-	if ctx == nil {
-		ctx = context.Background()
-	}
-
-	plan, err := buildBootstrapPlan(ctx, opts, runtime, originalDir)
-	if err != nil {
-		return err
-	}
-
-	printBootstrapPlan(plan)
-
-	if opts.PlanOnly {
-		bootstrapLog.Printf("Plan-only mode; skipping mutation for %s", opts.Repo)
-		return nil
-	}
-
-	if !plan.NeedsMutation {
-		bootstrapLog.Printf("Bootstrap already satisfied for %s; no mutation needed", opts.Repo)
-		fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Bootstrap already satisfied for "+opts.Repo))
-		return nil
-	}
-
-	if !opts.Yes {
-		if IsRunningInCI() {
-			return errors.New("--yes is required in CI when bootstrap would make changes. Example: gh aw bootstrap --repo OWNER/REPO --yes")
-		}
-		confirmed, err := runtime.confirmAction(
-			fmt.Sprintf("Apply bootstrap changes to %s?", plan.Repo),
-			"Apply changes",
-			"Cancel",
-		)
-		if err != nil {
-			return fmt.Errorf("failed to confirm bootstrap plan: %w", err)
-		}
-		if !confirmed {
-			return errors.New("bootstrap cancelled")
-		}
-	}
-
-	if plan.CreateRepo {
-		if err := runtime.createRepo(ctx, plan.Repo, opts.Visibility); err != nil {
-			return err
-		}
-		fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Created "+plan.Repo))
-	}
-
-	if plan.CloneRepo {
-		if err := runtime.cloneRepo(ctx, plan.Repo, plan.Dir); err != nil {
-			return err
-		}
-		fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Cloned %s into %s", plan.Repo, plan.Dir)))
-	}
-
-	if err := withWorkingDir(plan.Dir, func() error {
-		repositoryInitialized := false
-		missingMarkers, err := missingBootstrapInitMarkers(".", opts.EngineOverride)
-		if err != nil {
-			return err
-		}
-		if len(missingMarkers) > 0 {
-			if err := runtime.initRepo(InitOptions{
-				Ctx:              ctx,
-				Verbose:          opts.Verbose,
-				Engine:           opts.EngineOverride,
-				Skill:            true,
-				Agent:            true,
-				MCP:              true,
-				CodespaceRepos:   []string{},
-				CodespaceEnabled: false,
-				Completions:      false,
-				CreatePR:         false,
-			}); err != nil {
-				return fmt.Errorf("failed to initialize repository: %w", err)
-			}
-			repositoryInitialized = true
-			fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Initialized repository for agentic workflows"))
-		}
-
-		addedWorkflows := false
-		if len(plan.ResolvedSources) > 0 {
-			addOpts := AddOptions{
-				Verbose:        opts.Verbose,
-				EngineOverride: opts.EngineOverride,
-				Force:          opts.Force,
-			}
-			workflowsToAdd := plan.ResolvedSources
-			var skippedWorkflows []string
-			// Attached checkouts were already filtered during plan construction.
-			if !opts.Force && !plan.AttachedCheckout {
-				workflowsToAdd, skippedWorkflows, err = excludeExistingSourcedWorkflows(plan.ResolvedSources, addOpts)
-				if err != nil {
-					return fmt.Errorf("failed to inspect existing workflows: %w", err)
-				}
-			}
-			if len(skippedWorkflows) > 0 {
-				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Skipping already sourced workflows: "+strings.Join(skippedWorkflows, ", ")))
-			}
-			if len(workflowsToAdd) > 0 {
-				if _, err := runtime.addWorkflows(ctx, workflowsToAdd, addOpts); err != nil {
-					if repositoryInitialized {
-						return fmt.Errorf("failed to add workflows (%s): %w", bootstrapAddWorkflowsRetryHint, err)
-					}
-					return fmt.Errorf("failed to add workflows: %w", err)
-				}
-				addedWorkflows = true
-			}
-		}
-
-		if addedWorkflows && !opts.NoCompile {
-			if _, err := runtime.compileWorkflows(ctx, CompileConfig{
-				Verbose:        opts.Verbose,
-				EngineOverride: opts.EngineOverride,
-			}); err != nil {
-				return fmt.Errorf("failed to compile workflows: %w", err)
-			}
-			fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Compiled workflows"))
-		}
-
-		if plan.BootstrapProfile != nil && runtime.executeProfile != nil {
-			if err := runtime.executeProfile(ctx, bootstrapProfileRunConfig{
-				Repo:     plan.Repo,
-				RepoDir:  plan.Dir,
-				Sources:  resolveDeployWorkflowSpecs(opts.Sources, originalDir),
-				Profile:  plan.BootstrapProfile,
-				Yes:      opts.Yes,
-				PlanOnly: opts.PlanOnly,
-				Verbose:  opts.Verbose,
-				Force:    opts.Force,
-			}); err != nil {
-				return err
-			}
-		}
-
-		return nil
-	}); err != nil {
-		return err
-	}
-
-	fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Bootstrap completed for "+plan.Repo))
-	return nil
-}
-
-func normalizeBootstrapOptions(opts BootstrapOptions) BootstrapOptions {
-	if opts.Visibility == "" {
-		opts.Visibility = "private"
-	}
-	if opts.RequireOwnerType == "" {
-		opts.RequireOwnerType = "any"
-	}
-	return opts
-}
-
-func normalizeBootstrapRuntime(runtime bootstrapRuntime) bootstrapRuntime {
-	defaults := defaultBootstrapRuntime()
-	if runtime.confirmAction == nil {
-		runtime.confirmAction = defaults.confirmAction
-	}
-	if runtime.initRepo == nil {
-		runtime.initRepo = defaults.initRepo
-	}
-	if runtime.addWorkflows == nil {
-		runtime.addWorkflows = defaults.addWorkflows
-	}
-	if runtime.compileWorkflows == nil {
-		runtime.compileWorkflows = defaults.compileWorkflows
-	}
-	if runtime.resolveProfile == nil {
-		runtime.resolveProfile = defaults.resolveProfile
-	}
-	if runtime.profileNeedsPlan == nil {
-		runtime.profileNeedsPlan = defaults.profileNeedsPlan
-	}
-	if runtime.executeProfile == nil {
-		runtime.executeProfile = defaults.executeProfile
-	}
-	return runtime
-}
-
-func validateBootstrapOptions(opts BootstrapOptions) error {
-	if !isValidOwnerRepoSlug(opts.Repo) {
-		return errors.New("--repo must use the OWNER/REPO format. Example: --repo github/gh-aw")
-	}
-
-	switch opts.Visibility {
-	case "private", "public", "internal":
-	default:
-		return errors.New("--visibility must be one of: private, public, internal. Example: --visibility private")
-	}
-
-	switch opts.RequireOwnerType {
-	case "any", "org", "user":
-	default:
-		return errors.New("--require-owner-type must be one of: any, org, user. Example: --require-owner-type org")
-	}
-
-	return nil
-}
-
-func buildBootstrapPlan(ctx context.Context, opts BootstrapOptions, runtime bootstrapRuntime, originalDir string) (*bootstrapPlan, error) {
-	bootstrapLog.Printf("Building bootstrap plan: repo=%s, createRepo=%t, sources=%d", opts.Repo, opts.CreateRepo, len(opts.Sources))
-	if err := runtime.checkAuth(ctx); err != nil {
-		return nil, fmt.Errorf("failed to verify GitHub CLI authentication: %w", err)
-	}
-
-	plan := &bootstrapPlan{
-		Repo:            opts.Repo,
-		Dir:             resolveSetupCheckoutDir(opts.Repo, opts.Dir),
-		ResolvedSources: resolveDeployWorkflowSpecs(opts.Sources, originalDir),
-		CompileAfterAdd: len(opts.Sources) > 0 && !opts.NoCompile,
-	}
-
-	owner := strings.Split(opts.Repo, "/")[0]
-	if opts.RequireOwnerType != "any" {
-		ownerType, err := runtime.ownerType(ctx, owner)
-		if err != nil {
-			return nil, err
-		}
-		plan.OwnerType = ownerType
-		if normalizeSetupOwnerType(ownerType) != opts.RequireOwnerType {
-			return nil, fmt.Errorf("owner %s is %s, but --require-owner-type=%s was requested", owner, normalizeSetupOwnerType(ownerType), opts.RequireOwnerType)
-		}
-	}
-
-	repoExists, err := runtime.repoExists(ctx, opts.Repo)
-	if err != nil {
-		return nil, err
-	}
-	plan.RepoExists = repoExists
-	if !repoExists {
-		if !opts.CreateRepo {
-			return nil, fmt.Errorf("repository %s does not exist; rerun with --create-repo to create it", opts.Repo)
-		}
-		plan.CreateRepo = true
-	}
-
-	inspection, err := inspectSetupCheckout(plan.Dir, plan.Repo, runtime.dirOriginRepo)
-	if err != nil {
-		return nil, err
-	}
-	plan.CloneRepo = inspection.cloneNeeded
-	plan.AttachedCheckout = inspection.attached
-
-	if inspection.attached {
-		missingMarkers, err := missingBootstrapInitMarkers(plan.Dir, opts.EngineOverride)
-		if err != nil {
-			return nil, err
-		}
-		plan.InitMissingMarkers = missingMarkers
-		plan.InitNeeded = len(missingMarkers) > 0
-
-		if len(plan.ResolvedSources) > 0 {
-			addOpts := AddOptions{EngineOverride: opts.EngineOverride}
-			var workflowsToAdd []string
-			var skippedWorkflows []string
-			if opts.Force {
-				workflowsToAdd = plan.ResolvedSources
-			} else {
-				if err := withWorkingDir(plan.Dir, func() error {
-					var excludeErr error
-					workflowsToAdd, skippedWorkflows, excludeErr = excludeExistingSourcedWorkflows(plan.ResolvedSources, addOpts)
-					return excludeErr
-				}); err != nil {
-					return nil, err
-				}
-			}
-			plan.ResolvedSources = workflowsToAdd
-			plan.SkippedSources = skippedWorkflows
-			plan.CompileAfterAdd = len(workflowsToAdd) > 0 && !opts.NoCompile
-		}
-	}
-
-	if len(opts.Sources) > 0 && runtime.resolveProfile != nil {
-		profile, err := runtime.resolveProfile(ctx, opts.Sources)
-		if err != nil {
-			return nil, err
-		}
-		if profile != nil {
-			plan.BootstrapProfile = profile
-			profileNeedsPlan := runtime.profileNeedsPlan
-			if profileNeedsPlan == nil {
-				profileNeedsPlan = defaultBootstrapRuntime().profileNeedsPlan
-			}
-			needsAction, profileLines, err := profileNeedsPlan(ctx, plan.Repo, profile, opts.Sources, plan.RepoExists)
-			if err != nil {
-				return nil, err
-			}
-			plan.ProfileNeedsAction = needsAction
-			plan.ProfilePlanLines = append(plan.ProfilePlanLines, profileLines...)
-		}
-	}
-
-	plan.PlanLines = buildBootstrapPlanLines(plan, opts)
-	plan.NeedsMutation = plan.CreateRepo || plan.CloneRepo || plan.InitNeeded || len(plan.ResolvedSources) > 0 || plan.ProfileNeedsAction
-	bootstrapLog.Printf("Bootstrap plan built: createRepo=%t, cloneRepo=%t, attached=%t, initNeeded=%t, profileNeedsAction=%t, needsMutation=%t",
-		plan.CreateRepo, plan.CloneRepo, plan.AttachedCheckout, plan.InitNeeded, plan.ProfileNeedsAction, plan.NeedsMutation)
-
-	if !opts.PlanOnly && plan.AttachedCheckout && plan.NeedsMutation {
-		if err := withWorkingDir(plan.Dir, func() error {
-			return runtime.checkCleanWorktree(opts.Verbose)
-		}); err != nil {
-			return nil, err
-		}
-	}
-
-	return plan, nil
-}
-
-func missingBootstrapInitMarkers(baseDir string, engineOverride string) ([]string, error) {
-	markers := expectedBootstrapInitMarkers(engineOverride)
-	missing := make([]string, 0)
-	for _, marker := range markers {
-		ok, err := isBootstrapInitMarkerSatisfied(baseDir, marker)
-		if err != nil {
-			return nil, err
-		}
-		if !ok {
-			missing = append(missing, marker)
-		}
-	}
-	return missing, nil
-}
-
-func isBootstrapInitMarkerSatisfied(baseDir string, marker string) (bool, error) {
-	markerPath := filepath.Join(baseDir, filepath.FromSlash(marker))
-	info, err := os.Stat(markerPath)
-	if err != nil {
-		if errors.Is(err, os.ErrNotExist) {
-			return false, nil
-		}
-		return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-	}
-	if !info.Mode().IsRegular() {
-		return false, nil
-	}
-
-	switch marker {
-	case ".gitattributes":
-		content, err := os.ReadFile(markerPath)
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		return strings.Contains(string(content), constants.WorkflowsLockYmlGitAttributesEntry), nil
-	case bootstrapMCPConfigPath:
-		content, err := os.ReadFile(markerPath)
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		var config MCPConfig
-		if err := json.Unmarshal(content, &config); err != nil {
-			return false, nil
-		}
-		servers := config.MCPServers
-		if len(servers) == 0 {
-			servers = config.Servers
-		}
-		server, ok := servers["github-agentic-workflows"]
-		if !ok {
-			return false, nil
-		}
-		if strings.TrimSpace(server.Command) != "gh" {
-			return false, nil
-		}
-		return len(server.Args) >= 2 && server.Args[0] == "aw" && server.Args[1] == "mcp-server", nil
-	case bootstrapCopilotSetupPath:
-		content, err := os.ReadFile(markerPath)
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		steps := string(content)
-		hasLegacyInstall := strings.Contains(steps, "install-gh-aw.sh") ||
-			(strings.Contains(steps, "Install gh-aw extension") && strings.Contains(steps, "curl -fsSL"))
-		hasActionInstall := strings.Contains(steps, "actions/setup-cli")
-		return hasLegacyInstall || hasActionInstall, nil
-	case bootstrapAgenticSkillPath:
-		expected, err := buildAgenticWorkflowsSkillContent()
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		content, err := os.ReadFile(markerPath)
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		return strings.TrimSpace(string(content)) == strings.TrimSpace(expected), nil
-	case bootstrapAgenticAgentPath:
-		expected, err := buildAgenticWorkflowsAgentContent(baseDir)
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		content, err := os.ReadFile(markerPath)
-		if err != nil {
-			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
-		}
-		return strings.TrimSpace(string(content)) == strings.TrimSpace(expected), nil
-	default:
-		return info.Size() > 0, nil
-	}
-}
-
-func expectedBootstrapInitMarkers(engineOverride string) []string {
-	markers := []string{
-		".gitattributes",
-		".vscode/settings.json",
-	}
-	if engineOverride == "" || engineOverride == "copilot" {
-		markers = append(markers,
-			bootstrapAgenticSkillPath,
-			bootstrapAgenticAgentPath,
-			bootstrapMCPConfigPath,
-			bootstrapCopilotSetupPath,
-		)
-	}
-	return markers
-}
-
-func buildBootstrapPlanLines(plan *bootstrapPlan, opts BootstrapOptions) []string {
-	lines := []string{"Bootstrap plan for " + plan.Repo}
-
-	if plan.CreateRepo {
-		lines = append(lines, fmt.Sprintf("- create remote repository (%s)", opts.Visibility))
-		if plan.CloneRepo {
-			lines = append(lines, "- clone into "+plan.Dir)
-		}
-	} else if plan.CloneRepo {
-		lines = append(lines, "- clone existing repository into "+plan.Dir)
-	} else if plan.AttachedCheckout {
-		lines = append(lines, "- attach existing checkout at "+plan.Dir)
-	}
-
-	if plan.AttachedCheckout {
-		if plan.InitNeeded {
-			lines = append(lines, fmt.Sprintf("- initialize repository artifacts (missing: %s)", strings.Join(plan.InitMissingMarkers, ", ")))
-		} else {
-			lines = append(lines, "- initialization markers already present")
-		}
-	} else {
-		lines = append(lines, "- inspect init markers after clone")
-	}
-
-	if len(plan.ResolvedSources) > 0 {
-		lines = append(lines, fmt.Sprintf("- add %d workflow/package source(s)", len(plan.ResolvedSources)))
-		if plan.CompileAfterAdd {
-			lines = append(lines, "- compile workflows after adding sources")
-		}
-	}
-	if len(plan.SkippedSources) > 0 {
-		lines = append(lines, "- skip already sourced workflows: "+strings.Join(plan.SkippedSources, ", "))
-	}
-
-	if plan.BootstrapProfile != nil {
-		lines = append(lines, "- evaluate bootstrap actions from "+plan.BootstrapProfile.PackageID)
-		if plan.ProfileNeedsAction {
-			lines = append(lines, fmt.Sprintf("- apply bootstrap profile actions (%d action(s))", len(plan.BootstrapProfile.Profile.Config)))
-		} else {
-			lines = append(lines, "- bootstrap profile actions already satisfied")
-		}
-		lines = append(lines, plan.ProfilePlanLines...)
-	}
-
-	if plan.OwnerType != "" {
-		lines = append(lines, "- verified owner type: "+normalizeSetupOwnerType(plan.OwnerType))
-	}
-
-	if !plan.CreateRepo && !plan.CloneRepo && !plan.InitNeeded && len(plan.ResolvedSources) == 0 {
-		lines = append(lines, "- no changes required")
-	}
-
-	return lines
-}
-
-func printBootstrapPlan(plan *bootstrapPlan) {
-	for _, line := range plan.PlanLines {
-		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(line))
-	}
-	fmt.Fprintln(os.Stderr, "")
-}
-
-func withWorkingDir(dir string, fn func() error) error {
-	originalDir, err := os.Getwd()
-	if err != nil {
-		return fmt.Errorf("failed to read current directory: %w", err)
-	}
-	if err := os.Chdir(dir); err != nil {
-		return fmt.Errorf("failed to change directory to %s: %w", dir, err)
-	}
-	defer func() {
-		_ = os.Chdir(originalDir)
-	}()
-	return fn()
-}
diff --git a/pkg/cli/bootstrap_command.go b/pkg/cli/bootstrap_command.go
deleted file mode 100644
index e2c6510c664..00000000000
--- a/pkg/cli/bootstrap_command.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package cli
-
-import (
-	"fmt"
-
-	"github.com/github/gh-aw/pkg/constants"
-	"github.com/spf13/cobra"
-)
-
-func NewBootstrapCommand(validateEngine func(string) error) *cobra.Command {
-	cmd := &cobra.Command{
-		Use:    "bootstrap [source]...",
-		Short:  "Bootstrap a repository for agentic workflows",
-		Hidden: true,
-		Long: `Bootstrap a repository for agentic workflows by combining repository setup,
-checkout attachment or cloning, initialization, and optional workflow or package installation.
-
-This command is intentionally generic. It handles repository creation and initialization
-without assuming any product-specific auth, app registration, or secret layout.
-
-When you pass one or more sources, bootstrap will add them after initialization and then
-compile workflows unless you disable compilation with --no-compile.
-
-Sources use the same syntax as '` + string(constants.CLIExtensionPrefix) + ` add'.`,
-		Example: `  ` + string(constants.CLIExtensionPrefix) + ` bootstrap --repo octo-org/platform-ops --create-repo --visibility private
-  ` + string(constants.CLIExtensionPrefix) + ` bootstrap --repo octo-org/platform-ops github/central-agentic-ops/readiness
-  ` + string(constants.CLIExtensionPrefix) + ` bootstrap --repo octo-org/platform-ops ./local-workflow.md --yes
-  ` + string(constants.CLIExtensionPrefix) + ` bootstrap --repo octo-org/platform-ops --plan
-  ` + string(constants.CLIExtensionPrefix) + ` bootstrap --repo octo-org/platform-ops --engine claude --create-repo`,
-		RunE: func(cmd *cobra.Command, args []string) error {
-			engineOverride, _ := cmd.Flags().GetString("engine")
-			if err := validateEngine(engineOverride); err != nil {
-				return err
-			}
-
-			repo, _ := cmd.Flags().GetString("repo")
-			dir, _ := cmd.Flags().GetString("dir")
-			createRepo, _ := cmd.Flags().GetBool("create-repo")
-			visibility, _ := cmd.Flags().GetString("visibility")
-			requireOwnerType, _ := cmd.Flags().GetString("require-owner-type")
-			yes, _ := cmd.Flags().GetBool("yes")
-			planOnly, _ := cmd.Flags().GetBool("plan")
-			force, _ := cmd.Flags().GetBool("force")
-			noCompile, _ := cmd.Flags().GetBool("no-compile")
-			verbose, _ := cmd.Flags().GetBool("verbose")
-
-			if repo == "" {
-				return fmt.Errorf("--repo is required. Example: %s --repo github/gh-aw\n\nRun '%s --help' for usage information", cmd.CommandPath(), cmd.CommandPath())
-			}
-
-			bootstrapLog.Printf("Bootstrap command invoked: repo=%s, createRepo=%t, planOnly=%t, noCompile=%t, sources=%d", repo, createRepo, planOnly, noCompile, len(args))
-			return RunBootstrap(BootstrapOptions{
-				Ctx:              cmd.Context(),
-				Repo:             repo,
-				Dir:              dir,
-				CreateRepo:       createRepo,
-				Visibility:       visibility,
-				RequireOwnerType: requireOwnerType,
-				Yes:              yes,
-				PlanOnly:         planOnly,
-				EngineOverride:   engineOverride,
-				Sources:          args,
-				Force:            force,
-				NoCompile:        noCompile,
-				Verbose:          verbose,
-			})
-		},
-	}
-
-	cmd.Flags().String("repo", "", "Target repository (OWNER/REPO format)")
-	cmd.Flags().String("dir", "", "Local checkout directory (defaults to the repository name)")
-	cmd.Flags().Bool("create-repo", false, "Create the target repository when it does not exist")
-	cmd.Flags().String("visibility", "private", "Repository visibility for --create-repo: private, public, or internal")
-	cmd.Flags().String("require-owner-type", "any", "Require the repository owner to be org, user, or any")
-	cmd.Flags().BoolP("yes", "y", false, "Apply the bootstrap plan without confirmation")
-	cmd.Flags().Bool("plan", false, "Print the bootstrap plan without making changes")
-	cmd.Flags().BoolP("force", "f", false, "Allow added workflows to overwrite existing files when the add step runs")
-	cmd.Flags().Bool("no-compile", false, "Skip workflow compilation after adding sources")
-	addEngineFlag(cmd)
-	RegisterEngineFlagCompletion(cmd)
-
-	return cmd
-}
diff --git a/pkg/cli/bootstrap_config.go b/pkg/cli/bootstrap_config.go
index e932e3b49ec..bd8f2d766f9 100644
--- a/pkg/cli/bootstrap_config.go
+++ b/pkg/cli/bootstrap_config.go
@@ -8,6 +8,7 @@ import (
 	"os"
 
 	"github.com/github/gh-aw/pkg/console"
+	"github.com/github/gh-aw/pkg/gitutil"
 )
 
 // printBootstrapConfigTODO prints a TODO checklist of manual steps required by the
@@ -57,14 +58,14 @@ func printBootstrapConfigTODO(w io.Writer, profile *resolvedBootstrapProfile) {
 				secret = "COPILOT_GITHUB_TOKEN"
 			}
 			fmt.Fprintf(w, "  ☐ Set Copilot PAT secret: %s\n", secret)
+		case "commit-and-push":
+			fmt.Fprintf(w, "  ☐ Commit and push local changes — %s\n", action.Message)
 		case "handoff":
 			fmt.Fprintln(w, console.FormatInfoMessage(action.Message))
 		}
 	}
 
 	fmt.Fprintln(w, "")
-	fmt.Fprintln(w, console.FormatInfoMessage("Run 'gh aw bootstrap --repo OWNER/REPO' to apply these steps interactively."))
-	fmt.Fprintln(w, "")
 }
 
 // executeBootstrapConfigForAdd runs the bootstrap config actions interactively.
@@ -81,9 +82,14 @@ func executeBootstrapConfigForAdd(ctx context.Context, repo string, sources []st
 	bootstrapLog.Printf("Applying bootstrap config for add: repo=%s, package=%s, actions=%d, useCopilotRequests=%t", repo, profile.PackageID, len(profile.Profile.Config), useCopilotRequests)
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Applying post-installation steps from "+profile.PackageID+"..."))
+	repoDir, err := gitutil.FindGitRoot()
+	if err != nil {
+		bootstrapLog.Printf("Could not determine git root for add bootstrap config: %v", err)
+	}
 
 	return executeBootstrapProfile(ctx, bootstrapProfileRunConfig{
 		Repo:               repo,
+		RepoDir:            repoDir,
 		Sources:            sources,
 		Profile:            profile,
 		UseCopilotRequests: useCopilotRequests,
diff --git a/pkg/cli/bootstrap_integration_test.go b/pkg/cli/bootstrap_integration_test.go
deleted file mode 100644
index f7695ea23e6..00000000000
--- a/pkg/cli/bootstrap_integration_test.go
+++ /dev/null
@@ -1,136 +0,0 @@
-//go:build integration
-
-package cli
-
-import (
-	"os"
-	"os/exec"
-	"path/filepath"
-	"strings"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-type bootstrapIntegrationSetup struct {
-	base       *integrationTestSetup
-	repoDir    string
-	repoArg    string
-	fakeBinDir string
-	argsLog    string
-	pathEnv    string
-}
-
-func setupBootstrapIntegrationTest(t *testing.T) *bootstrapIntegrationSetup {
-	t.Helper()
-
-	base := setupIntegrationTest(t)
-	repoDir := filepath.Join(base.tempDir, "repo")
-	require.NoError(t, os.MkdirAll(repoDir, 0o755))
-
-	gitInitCmd := exec.Command("git", "init")
-	gitInitCmd.Dir = repoDir
-	output, err := gitInitCmd.CombinedOutput()
-	require.NoError(t, err, "Failed to run git init: %s", string(output))
-
-	gitNameCmd := exec.Command("git", "config", "user.name", "Bootstrap Test")
-	gitNameCmd.Dir = repoDir
-	output, err = gitNameCmd.CombinedOutput()
-	require.NoError(t, err, "Failed to set git user.name: %s", string(output))
-
-	gitEmailCmd := exec.Command("git", "config", "user.email", "bootstrap@example.com")
-	gitEmailCmd.Dir = repoDir
-	output, err = gitEmailCmd.CombinedOutput()
-	require.NoError(t, err, "Failed to set git user.email: %s", string(output))
-
-	gitRemoteCmd := exec.Command("git", "remote", "add", "origin", "https://github.com/octo/platform-ops.git")
-	gitRemoteCmd.Dir = repoDir
-	output, err = gitRemoteCmd.CombinedOutput()
-	require.NoError(t, err, "Failed to add git remote: %s", string(output))
-
-	fakeBinDir := filepath.Join(base.tempDir, "fake-bin")
-	require.NoError(t, os.MkdirAll(fakeBinDir, 0o755))
-	argsLog := filepath.Join(base.tempDir, "gh-args.log")
-	fakeGH := filepath.Join(fakeBinDir, "gh")
-	fakeGHScript := "#!/bin/sh\n" +
-		"printf '%s\\n' \"$*\" >> \"" + argsLog + "\"\n" +
-		"if [ \"$1\" = \"auth\" ] && [ \"$2\" = \"status\" ]; then\n" +
-		"  exit 0\n" +
-		"fi\n" +
-		"if [ \"$1\" = \"repo\" ] && [ \"$2\" = \"view\" ]; then\n" +
-		"  printf '%s\\n' 'octo/platform-ops'\n" +
-		"  exit 0\n" +
-		"fi\n" +
-		"printf 'unexpected gh invocation: %s\\n' \"$*\" >&2\n" +
-		"exit 1\n"
-	require.NoError(t, os.WriteFile(fakeGH, []byte(fakeGHScript), 0o755))
-
-	return &bootstrapIntegrationSetup{
-		base:       base,
-		repoDir:    repoDir,
-		repoArg:    "repo",
-		fakeBinDir: fakeBinDir,
-		argsLog:    argsLog,
-		pathEnv:    fakeBinDir + string(os.PathListSeparator) + os.Getenv("PATH"),
-	}
-}
-
-func TestBootstrapCommandPlanIntegration(t *testing.T) {
-	setup := setupBootstrapIntegrationTest(t)
-	defer setup.base.cleanup()
-
-	cmd := exec.Command(setup.base.binaryPath, "bootstrap", "--repo", "octo/platform-ops", "--dir", setup.repoArg, "--plan")
-	cmd.Dir = setup.base.tempDir
-	cmd.Env = append(os.Environ(), "PATH="+setup.pathEnv)
-	output, err := cmd.CombinedOutput()
-	outputStr := string(output)
-
-	require.NoError(t, err, "bootstrap --plan should succeed: %s", outputStr)
-	assert.Contains(t, outputStr, "Bootstrap plan for octo/platform-ops")
-	assert.Contains(t, outputStr, "attach existing checkout at repo")
-	assert.Contains(t, outputStr, "initialize repository artifacts")
-	assert.NoFileExists(t, filepath.Join(setup.repoDir, ".gitattributes"))
-
-	argsLog, err := os.ReadFile(setup.argsLog)
-	require.NoError(t, err)
-	assert.Contains(t, string(argsLog), "auth status")
-	assert.Contains(t, string(argsLog), "repo view octo/platform-ops --json nameWithOwner --jq .nameWithOwner")
-	assert.NotContains(t, string(argsLog), "repo clone")
-}
-
-func TestBootstrapCommandInitAndRerunIntegration(t *testing.T) {
-	setup := setupBootstrapIntegrationTest(t)
-	defer setup.base.cleanup()
-
-	runBootstrap := func(label string) string {
-		cmd := exec.Command(setup.base.binaryPath, "bootstrap", "--repo", "octo/platform-ops", "--dir", setup.repoArg, "--yes")
-		cmd.Dir = setup.base.tempDir
-		cmd.Env = append(os.Environ(), "PATH="+setup.pathEnv)
-		output, err := cmd.CombinedOutput()
-		outputStr := string(output)
-		require.NoError(t, err, "%s should succeed: %s", label, outputStr)
-		return outputStr
-	}
-
-	firstOutput := runBootstrap("first bootstrap run")
-	assert.Contains(t, firstOutput, "Initialized repository for agentic workflows")
-	assert.Contains(t, firstOutput, "Bootstrap completed for octo/platform-ops")
-
-	assert.FileExists(t, filepath.Join(setup.repoDir, ".gitattributes"))
-	assert.FileExists(t, filepath.Join(setup.repoDir, ".vscode", "settings.json"))
-	assert.FileExists(t, filepath.Join(setup.repoDir, ".github", "skills", "agentic-workflows", "SKILL.md"))
-	assert.FileExists(t, filepath.Join(setup.repoDir, ".github", "agents", "agentic-workflows.md"))
-	assert.FileExists(t, filepath.Join(setup.repoDir, ".github", "mcp.json"))
-	assert.FileExists(t, filepath.Join(setup.repoDir, ".github", "workflows", "copilot-setup-steps.yml"))
-
-	secondOutput := runBootstrap("second bootstrap run")
-	assert.Contains(t, secondOutput, "Bootstrap already satisfied for octo/platform-ops")
-	assert.NotContains(t, secondOutput, "Initialized repository for agentic workflows")
-
-	argsLog, err := os.ReadFile(setup.argsLog)
-	require.NoError(t, err)
-	assert.NotContains(t, string(argsLog), "repo clone")
-	assert.GreaterOrEqual(t, strings.Count(string(argsLog), "auth status"), 2)
-	assert.GreaterOrEqual(t, strings.Count(string(argsLog), "repo view octo/platform-ops --json nameWithOwner --jq .nameWithOwner"), 2)
-}
diff --git a/pkg/cli/bootstrap_profile_manifest.go b/pkg/cli/bootstrap_profile_manifest.go
index af00794d447..747ea5c62df 100644
--- a/pkg/cli/bootstrap_profile_manifest.go
+++ b/pkg/cli/bootstrap_profile_manifest.go
@@ -1,16 +1,12 @@
 package cli
 
 import (
-	"context"
 	"errors"
 	"fmt"
-	"os"
-	"path/filepath"
-	"sort"
 	"strings"
 )
 
-const bootstrapActionTypeExample = "require-owner-type, repo-variable, repo-secret, github-app, copilot-auth, or handoff"
+const bootstrapActionTypeExample = "require-owner-type, repo-variable, repo-secret, github-app, copilot-auth, commit-and-push, or handoff"
 
 type repositoryPackageBootstrap struct {
 	Config []repositoryPackageBootstrapAction
@@ -51,138 +47,6 @@ type resolvedBootstrapProfile struct {
 	Profile   *repositoryPackageBootstrap
 }
 
-func resolveBootstrapProfileFromSources(ctx context.Context, sources []string) (*resolvedBootstrapProfile, error) {
-	bootstrapLog.Printf("Resolving bootstrap profile from %d source(s)", len(sources))
-	profiles := make([]*resolvedBootstrapProfile, 0, 1)
-	seenPackageIDs := make(map[string]struct{})
-
-	for _, source := range sources {
-		if localProfile, err := resolveLocalBootstrapProfileFromSource(source); err != nil {
-			return nil, err
-		} else if localProfile != nil {
-			if _, exists := seenPackageIDs[localProfile.PackageID]; exists {
-				continue
-			}
-			seenPackageIDs[localProfile.PackageID] = struct{}{}
-			profiles = append(profiles, localProfile)
-			continue
-		}
-
-		repoSpec, ok, repoErr := parseRepositoryPackageSpec(source)
-		if !ok {
-			continue
-		}
-		if repoErr != nil {
-			return nil, repoErr
-		}
-
-		pkg, err := resolveRepositoryPackage(ctx, repoSpec, explicitHostForRepo(repoSpec.RepoSlug))
-		if err != nil {
-			if repoSpec.PackagePath == "" || !isRepositoryPackageManifestNotFound(err) {
-				return nil, err
-			}
-			continue
-		}
-		if pkg.Bootstrap == nil {
-			continue
-		}
-
-		packageID := repositoryPackageIdentifier(repoSpec.RepoSlug, repoSpec.PackagePath)
-		if _, exists := seenPackageIDs[packageID]; exists {
-			continue
-		}
-		seenPackageIDs[packageID] = struct{}{}
-
-		profiles = append(profiles, &resolvedBootstrapProfile{
-			PackageID: packageID,
-			Source:    source,
-			Profile:   pkg.Bootstrap,
-		})
-	}
-
-	if len(profiles) == 0 {
-		bootstrapLog.Print("No bootstrap profile matched the selected sources")
-		return nil, nil
-	}
-	if len(profiles) == 1 {
-		bootstrapLog.Printf("Resolved bootstrap profile: packageID=%s, actions=%d", profiles[0].PackageID, len(profiles[0].Profile.Config))
-		return profiles[0], nil
-	}
-
-	packageIDs := make([]string, 0, len(profiles))
-	for _, profile := range profiles {
-		packageIDs = append(packageIDs, profile.PackageID)
-	}
-	sort.Strings(packageIDs)
-
-	return nil, fmt.Errorf("multiple bootstrap profiles matched the selected sources: %s; select a single package profile or split the bootstrap into separate runs", strings.Join(packageIDs, ", "))
-}
-
-func resolveLocalBootstrapProfileFromSource(source string) (*resolvedBootstrapProfile, error) {
-	if !isLocalWorkflowPath(source) {
-		return nil, nil
-	}
-
-	resolvedPath, err := filepath.Abs(source)
-	if err != nil {
-		return nil, fmt.Errorf("resolve local bootstrap profile %q: %w", source, err)
-	}
-
-	manifestPath, packageID, err := localBootstrapManifestPath(resolvedPath)
-	if err != nil {
-		if errors.Is(err, os.ErrNotExist) {
-			return nil, nil
-		}
-		return nil, err
-	}
-	if manifestPath == "" {
-		return nil, nil
-	}
-
-	content, err := os.ReadFile(manifestPath)
-	if err != nil {
-		if errors.Is(err, os.ErrNotExist) {
-			return nil, nil
-		}
-		return nil, fmt.Errorf("read local bootstrap manifest %q: %w", manifestPath, err)
-	}
-
-	manifest, _, err := parseRepositoryPackageManifest(manifestPath, content)
-	if err != nil {
-		return nil, err
-	}
-	if manifest.Bootstrap == nil {
-		return nil, nil
-	}
-
-	return &resolvedBootstrapProfile{
-		PackageID: packageID,
-		Source:    source,
-		Profile:   manifest.Bootstrap,
-	}, nil
-}
-
-func localBootstrapManifestPath(resolvedPath string) (string, string, error) {
-	info, err := os.Stat(resolvedPath)
-	if err != nil {
-		return "", "", err
-	}
-
-	if info.IsDir() {
-		manifestPath := filepath.Join(resolvedPath, repositoryPackageManifestFileName)
-		if _, err := os.Stat(manifestPath); err != nil {
-			return "", "", err
-		}
-		return manifestPath, filepath.Clean(resolvedPath), nil
-	}
-
-	if filepath.Base(resolvedPath) != repositoryPackageManifestFileName {
-		return "", "", nil
-	}
-
-	return resolvedPath, filepath.Clean(filepath.Dir(resolvedPath)), nil
-}
-
 func extractManifestConfig(value any, manifestPath string) (*repositoryPackageBootstrap, error) {
 	configItems, ok := value.([]any)
 	if !ok {
@@ -344,6 +208,10 @@ func parseManifestBootstrapAction(actionType string, actionMap map[string]any, m
 		if action.Strategy != "prompt-if-actions-auth-unavailable" {
 			return repositoryPackageBootstrapAction{}, fmt.Errorf("invalid Agentic Workflow manifest %q: config[%d].strategy must be 'prompt-if-actions-auth-unavailable'. Example: { type: copilot-auth, strategy: prompt-if-actions-auth-unavailable }", manifestPath, index)
 		}
+	case "commit-and-push":
+		if action.Message == "" {
+			return repositoryPackageBootstrapAction{}, fmt.Errorf("invalid Agentic Workflow manifest %q: config[%d].message is required when type=commit-and-push. Example: { type: commit-and-push, message: Bootstrap repository changes }", manifestPath, index)
+		}
 	case "handoff":
 		if action.Message == "" {
 			return repositoryPackageBootstrapAction{}, fmt.Errorf("invalid Agentic Workflow manifest %q: config[%d].message is required when type=handoff. Example: { type: handoff, message: Continue with repository-specific setup. }", manifestPath, index)
diff --git a/pkg/cli/bootstrap_profile_runner.go b/pkg/cli/bootstrap_profile_runner.go
index ec1c31facea..ff1118bf545 100644
--- a/pkg/cli/bootstrap_profile_runner.go
+++ b/pkg/cli/bootstrap_profile_runner.go
@@ -100,54 +100,12 @@ type bootstrapGitHubAppExchangeResponse struct {
 	Name     string `json:"name"`
 }
 
-type bootstrapGitHubAppRepositoryInstallation struct {
-	ClientID string `json:"client_id"`
-	AppID    int64  `json:"app_id"`
-	AppSlug  string `json:"app_slug"`
-	ID       int64  `json:"id"`
-}
-
-func buildBootstrapProfilePlan(ctx context.Context, repo string, profile *resolvedBootstrapProfile, sources []string, repoReady bool) (bool, []string, error) {
-	if profile == nil || profile.Profile == nil {
-		return false, nil, nil
-	}
-
-	lines := make([]string, 0, len(profile.Profile.Config))
-	if !repoReady {
-		for _, action := range profile.Profile.Config {
-			if err := validateBootstrapActionPreRepo(ctx, repo, action); err != nil {
-				return false, nil, err
-			}
-			if bootstrapActionCanMutate(action, sources) {
-				lines = append(lines, "- bootstrap profile will configure "+bootstrapActionPlanLabel(action))
-			}
-		}
-		return len(lines) > 0, lines, nil
-	}
-
-	state, err := bootstrapProfileState(ctx, repo)
-	if err != nil {
-		return false, nil, err
-	}
-	usesActionsToken, err := profileSourcesUseActionsTokenCopilotAuth(ctx, sources)
-	if err != nil {
-		return false, nil, err
-	}
-
-	needsMutation := false
-	for _, action := range profile.Profile.Config {
-		pending, err := bootstrapActionNeedsMutation(ctx, repo, action, state, usesActionsToken)
-		if err != nil {
-			return false, nil, err
-		}
-		if pending {
-			needsMutation = true
-			lines = append(lines, "- bootstrap profile will configure "+bootstrapActionPlanLabel(action))
-		}
-	}
-
-	bootstrapLog.Printf("Built bootstrap profile plan: repo=%s, needsMutation=%t, planLines=%d", repo, needsMutation, len(lines))
-	return needsMutation, lines, nil
+type bootstrapGitHubAppUserInstallation struct {
+	ID                  int64
+	ClientID            string
+	AppID               string
+	AppSlug             string
+	RepositorySelection string
 }
 
 func executeBootstrapProfile(ctx context.Context, config bootstrapProfileRunConfig) error {
@@ -217,6 +175,10 @@ func executeBootstrapProfile(ctx context.Context, config bootstrapProfileRunConf
 			if applied {
 				state.secrets[action.Secret] = struct{}{}
 			}
+		case "commit-and-push":
+			if err := runBootstrapCommitAndPushAction(ctx, config.RepoDir, action); err != nil {
+				return err
+			}
 		case "handoff":
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(action.Message))
 		default:
@@ -267,6 +229,8 @@ func bootstrapActionNeedsMutation(ctx context.Context, repo string, action repos
 	case "copilot-auth":
 		_, hasSecret := state.secrets[action.Secret]
 		return !hasSecret && !usesActionsToken, nil
+	case "commit-and-push":
+		return true, nil
 	case "handoff":
 		return false, nil
 	default:
@@ -274,37 +238,54 @@ func bootstrapActionNeedsMutation(ctx context.Context, repo string, action repos
 	}
 }
 
-func validateBootstrapActionPreRepo(ctx context.Context, repo string, action repositoryPackageBootstrapAction) error {
-	if action.Type == "require-owner-type" {
-		return runBootstrapRequireOwnerType(ctx, repo, action)
+func runBootstrapCommitAndPushAction(ctx context.Context, repoDir string, action repositoryPackageBootstrapAction) error {
+	if repoDir == "" {
+		return errors.New("bootstrap commit-and-push requires a local checkout directory. Example: rerun from a git checkout and then rerun gh aw add from that checkout")
 	}
+
+	pending, err := bootstrapRepoHasPendingChanges(ctx, repoDir)
+	if err != nil {
+		return err
+	}
+	if !pending {
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Skipping commit and push because the local checkout is already clean."))
+		return nil
+	}
+
+	if _, err := runBootstrapGitCommand(ctx, repoDir, "add", "-A"); err != nil {
+		return err
+	}
+	if _, err := runBootstrapGitCommand(ctx, repoDir, "commit", "-m", action.Message); err != nil {
+		return err
+	}
+	branch, err := getCurrentBranchIn(repoDir)
+	if err != nil {
+		return fmt.Errorf("failed to determine current branch for bootstrap commit-and-push: %w", err)
+	}
+	if _, err := runBootstrapGitCommand(ctx, repoDir, "push", "-u", "origin", branch); err != nil {
+		return err
+	}
+
+	fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Committed and pushed bootstrap changes"))
 	return nil
 }
 
-func bootstrapActionCanMutate(action repositoryPackageBootstrapAction, sources []string) bool {
-	switch action.Type {
-	case "repo-variable", "repo-secret", "github-app":
-		return true
-	case "copilot-auth":
-		return true
-	default:
-		return false
+func bootstrapRepoHasPendingChanges(ctx context.Context, repoDir string) (bool, error) {
+	output, err := runBootstrapGitCommand(ctx, repoDir, "status", "--porcelain")
+	if err != nil {
+		return false, err
 	}
+	return strings.TrimSpace(string(output)) != "", nil
 }
 
-func bootstrapActionPlanLabel(action repositoryPackageBootstrapAction) string {
-	switch action.Type {
-	case "repo-variable":
-		return "repository variable " + action.Name
-	case "repo-secret":
-		return "repository secret " + action.Name
-	case "github-app":
-		return fmt.Sprintf("GitHub App credentials (%s, %s)", action.AppIDVariable, action.PrivateKeySecret)
-	case "copilot-auth":
-		return "Copilot secret " + action.Secret
-	default:
-		return action.Type
+func runBootstrapGitCommand(ctx context.Context, repoDir string, args ...string) ([]byte, error) {
+	cmd := exec.CommandContext(ctx, "git", args...)
+	cmd.Dir = repoDir
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return output, fmt.Errorf("failed to run git %s in %s: %w\n%s", strings.Join(args, " "), repoDir, err, strings.TrimSpace(string(output)))
 	}
+	return output, nil
 }
 
 func runBootstrapRequireOwnerType(ctx context.Context, repo string, action repositoryPackageBootstrapAction) error {
@@ -733,21 +714,97 @@ func waitForBootstrapGitHubAppInstallation(ctx context.Context, repo string, cre
 }
 
 func bootstrapGitHubAppInstalled(ctx context.Context, repo string, createdApp *bootstrapCreatedGitHubApp) (bool, error) {
-	output, err := runBootstrapGHContext(ctx, "Checking GitHub App installation...", "api", "/repos/"+repo+"/installation")
+	installations, err := listBootstrapUserInstallations(ctx)
 	if err != nil {
 		return false, err
 	}
-	var payload bootstrapGitHubAppRepositoryInstallation
-	if err := json.Unmarshal(output, &payload); err != nil {
-		return false, err
+	for _, installation := range installations {
+		if !bootstrapGitHubAppInstallationMatches(installation, createdApp) {
+			continue
+		}
+		if installation.RepositorySelection != "selected" || repo == "" {
+			return installation.ID > 0, nil
+		}
+		repositories, err := listBootstrapUserInstallationRepositories(ctx, installation.ID)
+		if err != nil {
+			return false, err
+		}
+		for _, repository := range repositories {
+			if strings.EqualFold(repository, repo) {
+				return true, nil
+			}
+		}
+		return false, nil
+	}
+	return false, nil
+}
+
+func listBootstrapUserInstallations(ctx context.Context) ([]bootstrapGitHubAppUserInstallation, error) {
+	output, err := runBootstrapGHContext(
+		ctx,
+		"Checking GitHub App installation...",
+		"api",
+		"/user/installations?per_page=100",
+		"--paginate",
+		"--jq",
+		`.installations[] | [(.id|tostring), (.client_id // ""), (.app_id|tostring), .app_slug, .repository_selection] | @tsv`,
+	)
+	if err != nil {
+		return nil, err
 	}
-	if payload.ClientID != "" && payload.ClientID == createdApp.ClientID {
-		return payload.ID > 0, nil
+	trimmed := strings.TrimSpace(string(output))
+	if trimmed == "" {
+		return nil, nil
 	}
-	if payload.AppSlug == createdApp.Slug || strconv.FormatInt(payload.AppID, 10) == createdApp.AppID {
-		return payload.ID > 0, nil
+	lines := strings.Split(trimmed, "\n")
+	installations := make([]bootstrapGitHubAppUserInstallation, 0, len(lines))
+	for _, line := range lines {
+		fields := strings.Split(line, "\t")
+		if len(fields) != 5 {
+			return nil, fmt.Errorf("failed to parse user installation response line %q", line)
+		}
+		installationID, err := strconv.ParseInt(fields[0], 10, 64)
+		if err != nil {
+			return nil, fmt.Errorf("failed to parse user installation id %q: %w", fields[0], err)
+		}
+		installations = append(installations, bootstrapGitHubAppUserInstallation{
+			ID:                  installationID,
+			ClientID:            fields[1],
+			AppID:               fields[2],
+			AppSlug:             fields[3],
+			RepositorySelection: fields[4],
+		})
+	}
+	return installations, nil
+}
+
+func listBootstrapUserInstallationRepositories(ctx context.Context, installationID int64) ([]string, error) {
+	output, err := runBootstrapGHContext(
+		ctx,
+		"Checking GitHub App installation repositories...",
+		"api",
+		fmt.Sprintf("/user/installations/%d/repositories?per_page=100", installationID),
+		"--paginate",
+		"--jq",
+		".repositories[].full_name",
+	)
+	if err != nil {
+		return nil, err
 	}
-	return false, nil
+	return parseBootstrapNames(output), nil
+}
+
+func bootstrapGitHubAppInstallationMatches(installation bootstrapGitHubAppUserInstallation, createdApp *bootstrapCreatedGitHubApp) bool {
+	if createdApp == nil {
+		return false
+	}
+	if installation.ClientID != "" && createdApp.ClientID != "" && installation.ClientID == createdApp.ClientID {
+		return true
+	}
+	if installation.AppSlug != "" && createdApp.Slug != "" && installation.AppSlug == createdApp.Slug {
+		return true
+	}
+	return installation.AppID != "" && createdApp.AppID != "" && installation.AppID == createdApp.AppID
 }
 
 func listBootstrapRepoVariableNames(ctx context.Context, repo string) ([]string, error) {
diff --git a/pkg/cli/bootstrap_profile_runner_test.go b/pkg/cli/bootstrap_profile_runner_test.go
index 35cca4abdf4..498d0bd6b08 100644
--- a/pkg/cli/bootstrap_profile_runner_test.go
+++ b/pkg/cli/bootstrap_profile_runner_test.go
@@ -6,6 +6,7 @@ import (
 	"context"
 	"errors"
 	"os"
+	"os/exec"
 	"path/filepath"
 	"slices"
 	"strings"
@@ -276,6 +277,68 @@ func TestRunBootstrapGitHubAppAction_CreateOverwritesPartialCredentialPair(t *te
 	}
 }
 
+func TestRunBootstrapCommitAndPushAction_CommitsAndPushesChanges(t *testing.T) {
+	repoDir := initBootstrapGitRepo(t)
+	remoteDir := t.TempDir()
+
+	runRepoGit := func(args ...string) string {
+		t.Helper()
+		cmd := exec.Command("git", args...)
+		cmd.Dir = repoDir
+		output, err := cmd.CombinedOutput()
+		if err != nil {
+			t.Fatalf("git %s failed: %v\n%s", strings.Join(args, " "), err, string(output))
+		}
+		return string(output)
+	}
+
+	cmd := exec.Command("git", "init", "--bare", remoteDir)
+	if output, err := cmd.CombinedOutput(); err != nil {
+		t.Fatalf("git init --bare failed: %v\n%s", err, string(output))
+	}
+
+	runRepoGit("config", "user.name", "Bootstrap Test")
+	runRepoGit("config", "user.email", "bootstrap@example.com")
+	runRepoGit("remote", "add", "origin", remoteDir)
+	if err := os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("initial\n"), 0o644); err != nil {
+		t.Fatalf("write initial file: %v", err)
+	}
+	runRepoGit("add", "README.md")
+	runRepoGit("commit", "-m", "initial")
+	if err := os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("updated\n"), 0o644); err != nil {
+		t.Fatalf("write updated file: %v", err)
+	}
+
+	err := runBootstrapCommitAndPushAction(context.Background(), repoDir, repositoryPackageBootstrapAction{
+		Type:    "commit-and-push",
+		Message: "Bootstrap repository changes",
+	})
+	if err != nil {
+		t.Fatalf("runBootstrapCommitAndPushAction returned error: %v", err)
+	}
+
+	if got := strings.TrimSpace(runRepoGit("log", "--format=%s", "-1")); got != "Bootstrap repository changes" {
+		t.Fatalf("unexpected commit message: %q", got)
+	}
+	if got := strings.TrimSpace(runRepoGit("status", "--porcelain")); got != "" {
+		t.Fatalf("expected clean worktree after commit-and-push, got %q", got)
+	}
+
+	branch, err := getCurrentBranchIn(repoDir)
+	if err != nil {
+		t.Fatalf("getCurrentBranchIn returned error: %v", err)
+	}
+	localHead := strings.TrimSpace(runRepoGit("rev-parse", "HEAD"))
+	remoteHeadCmd := exec.Command("git", "--git-dir", remoteDir, "rev-parse", "refs/heads/"+branch)
+	remoteHeadOutput, err := remoteHeadCmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to read remote branch head: %v\n%s", err, string(remoteHeadOutput))
+	}
+	if got := strings.TrimSpace(string(remoteHeadOutput)); got != localHead {
+		t.Fatalf("expected remote head %q to match local head %q", got, localHead)
+	}
+}
+
 func TestBootstrapRepositoryInputEnvNames(t *testing.T) {
 	if got := bootstrapRepositoryVariableEnvName("CENTRAL_AGENTIC_OPS_MODE"); got != "GH_AW_BOOTSTRAP_VAR_CENTRAL_AGENTIC_OPS_MODE" {
 		t.Fatalf("unexpected variable env name: %s", got)
@@ -326,3 +389,70 @@ func TestIsRetryableBootstrapGitHubAppInstallationError(t *testing.T) {
 		t.Fatal("expected HTTP 403 to be non-retryable")
 	}
 }
+
+func TestBootstrapGitHubAppInstalled_UsesUserInstallationsForAllRepositories(t *testing.T) {
+	originalRunGH := runBootstrapGHContext
+	t.Cleanup(func() {
+		runBootstrapGHContext = originalRunGH
+	})
+
+	var calls []string
+	runBootstrapGHContext = func(_ context.Context, _ string, args ...string) ([]byte, error) {
+		calls = append(calls, strings.Join(args, " "))
+		if len(args) >= 2 && args[0] == "api" && args[1] == "/user/installations?per_page=100" {
+			return []byte("123\tIv1.client\t987\tmy-mona-org-agenticops\tall\n"), nil
+		}
+		return nil, errors.New("unexpected gh api call")
+	}
+
+	installed, err := bootstrapGitHubAppInstalled(context.Background(), "my-mona-org/agenticops", &bootstrapCreatedGitHubApp{
+		ClientID: "Iv1.client",
+		AppID:    "987",
+		Slug:     "my-mona-org-agenticops",
+	})
+	if err != nil {
+		t.Fatalf("bootstrapGitHubAppInstalled returned error: %v", err)
+	}
+	if !installed {
+		t.Fatal("expected installation to be detected")
+	}
+	if len(calls) != 1 {
+		t.Fatalf("expected 1 gh api call, got %d", len(calls))
+	}
+	if strings.Contains(calls[0], "/repos/my-mona-org/agenticops/installation") {
+		t.Fatalf("expected user installations endpoint, got %q", calls[0])
+	}
+}
+
+func TestBootstrapGitHubAppInstalled_SelectedInstallationChecksRepositoryMembership(t *testing.T) {
+	originalRunGH := runBootstrapGHContext
+	t.Cleanup(func() {
+		runBootstrapGHContext = originalRunGH
+	})
+
+	var calls []string
+	runBootstrapGHContext = func(_ context.Context, _ string, args ...string) ([]byte, error) {
+		calls = append(calls, strings.Join(args, " "))
+		if len(args) >= 2 && args[0] == "api" && args[1] == "/user/installations?per_page=100" {
+			return []byte("123\t\t987\tmy-mona-org-agenticops\tselected\n"), nil
+		}
+		if len(args) >= 2 && args[0] == "api" && args[1] == "/user/installations/123/repositories?per_page=100" {
+			return []byte("my-mona-org/agenticops\n"), nil
+		}
+		return nil, errors.New("unexpected gh api call")
+	}
+
+	installed, err := bootstrapGitHubAppInstalled(context.Background(), "my-mona-org/agenticops", &bootstrapCreatedGitHubApp{
+		AppID: "987",
+		Slug:  "my-mona-org-agenticops",
+	})
+	if err != nil {
+		t.Fatalf("bootstrapGitHubAppInstalled returned error: %v", err)
+	}
+	if !installed {
+		t.Fatal("expected selected installation to include target repository")
+	}
+	if len(calls) != 2 {
+		t.Fatalf("expected 2 gh api calls, got %d", len(calls))
+	}
+}
diff --git a/pkg/cli/bootstrap_shared.go b/pkg/cli/bootstrap_shared.go
new file mode 100644
index 00000000000..6a89fe6db7d
--- /dev/null
+++ b/pkg/cli/bootstrap_shared.go
@@ -0,0 +1,143 @@
+package cli
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/github/gh-aw/pkg/constants"
+	"github.com/github/gh-aw/pkg/logger"
+)
+
+var bootstrapLog = logger.New("cli:bootstrap")
+
+const (
+	bootstrapMCPConfigPath    = ".github/mcp.json"
+	bootstrapCopilotSetupPath = ".github/workflows/copilot-setup-steps.yml"
+	bootstrapAgenticSkillPath = ".github/skills/agentic-workflows/SKILL.md"
+	bootstrapAgenticAgentPath = ".github/agents/agentic-workflows.md"
+)
+
+func missingBootstrapInitMarkers(baseDir string, engineOverride string) ([]string, error) {
+	markers := expectedBootstrapInitMarkers(engineOverride)
+	missing := make([]string, 0)
+	for _, marker := range markers {
+		ok, err := isBootstrapInitMarkerSatisfied(baseDir, marker)
+		if err != nil {
+			return nil, err
+		}
+		if !ok {
+			missing = append(missing, marker)
+		}
+	}
+	return missing, nil
+}
+
+func isBootstrapInitMarkerSatisfied(baseDir string, marker string) (bool, error) {
+	markerPath := filepath.Join(baseDir, filepath.FromSlash(marker))
+	info, err := os.Stat(markerPath)
+	if err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			return false, nil
+		}
+		return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+	}
+	if !info.Mode().IsRegular() {
+		return false, nil
+	}
+
+	switch marker {
+	case ".gitattributes":
+		content, err := os.ReadFile(markerPath)
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		return strings.Contains(string(content), constants.WorkflowsLockYmlGitAttributesEntry), nil
+	case bootstrapMCPConfigPath:
+		content, err := os.ReadFile(markerPath)
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		var config MCPConfig
+		if err := json.Unmarshal(content, &config); err != nil {
+			return false, nil
+		}
+		servers := config.MCPServers
+		if len(servers) == 0 {
+			servers = config.Servers
+		}
+		server, ok := servers["github-agentic-workflows"]
+		if !ok {
+			return false, nil
+		}
+		if strings.TrimSpace(server.Command) != "gh" {
+			return false, nil
+		}
+		return len(server.Args) >= 2 && server.Args[0] == "aw" && server.Args[1] == "mcp-server", nil
+	case bootstrapCopilotSetupPath:
+		content, err := os.ReadFile(markerPath)
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		steps := string(content)
+		hasLegacyInstall := strings.Contains(steps, "install-gh-aw.sh") ||
+			(strings.Contains(steps, "Install gh-aw extension") && strings.Contains(steps, "curl -fsSL"))
+		hasActionInstall := strings.Contains(steps, "actions/setup-cli")
+		return hasLegacyInstall || hasActionInstall, nil
+	case bootstrapAgenticSkillPath:
+		expected, err := buildAgenticWorkflowsSkillContent()
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		content, err := os.ReadFile(markerPath)
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		return strings.TrimSpace(string(content)) == strings.TrimSpace(expected), nil
+	case bootstrapAgenticAgentPath:
+		expected, err := buildAgenticWorkflowsAgentContent(baseDir)
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		content, err := os.ReadFile(markerPath)
+		if err != nil {
+			return false, fmt.Errorf("failed to inspect %s: %w", marker, err)
+		}
+		return strings.TrimSpace(string(content)) == strings.TrimSpace(expected), nil
+	default:
+		return info.Size() > 0, nil
+	}
+}
+
+func expectedBootstrapInitMarkers(engineOverride string) []string {
+	markers := []string{
+		".gitattributes",
+		".vscode/settings.json",
+	}
+	if engineOverride == "" || engineOverride == "copilot" {
+		markers = append(markers,
+			bootstrapAgenticSkillPath,
+			bootstrapAgenticAgentPath,
+			bootstrapMCPConfigPath,
+			bootstrapCopilotSetupPath,
+		)
+	}
+	return markers
+}
+
+func withWorkingDir(dir string, fn func() error) error {
+	originalDir, err := os.Getwd()
+	if err != nil {
+		return fmt.Errorf("failed to read current directory: %w", err)
+	}
+	if err := os.Chdir(dir); err != nil {
+		return fmt.Errorf("failed to change directory to %s: %w", dir, err)
+	}
+	defer func() {
+		_ = os.Chdir(originalDir)
+	}()
+	return fn()
+}
diff --git a/pkg/cli/bootstrap_test.go b/pkg/cli/bootstrap_test.go
deleted file mode 100644
index 8a5faad0495..00000000000
--- a/pkg/cli/bootstrap_test.go
+++ /dev/null
@@ -1,927 +0,0 @@
-//go:build !integration
-
-package cli
-
-import (
-	"context"
-	"errors"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"slices"
-	"strings"
-	"testing"
-
-	"github.com/github/gh-aw/pkg/constants"
-	"github.com/github/gh-aw/pkg/testutil"
-	"github.com/github/gh-aw/pkg/workflow"
-)
-
-func TestNewBootstrapCommand(t *testing.T) {
-	cmd := NewBootstrapCommand(func(string) error { return nil })
-	if cmd == nil {
-		t.Fatal("NewBootstrapCommand returned nil")
-	}
-	if cmd.Use != "bootstrap [source]..." {
-		t.Fatalf("unexpected use: %s", cmd.Use)
-	}
-	if !cmd.Hidden {
-		t.Fatal("expected bootstrap command to be hidden")
-	}
-	if cmd.Flags().Lookup("repo") == nil {
-		t.Fatal("expected --repo flag")
-	}
-	if cmd.Flags().Lookup("create-repo") == nil {
-		t.Fatal("expected --create-repo flag")
-	}
-	if cmd.Flags().Lookup("visibility") == nil {
-		t.Fatal("expected --visibility flag")
-	}
-	if cmd.Flags().Lookup("plan") == nil {
-		t.Fatal("expected --plan flag")
-	}
-	if cmd.Flags().Lookup("no-compile") == nil {
-		t.Fatal("expected --no-compile flag")
-	}
-	if cmd.Flags().Lookup("engine") == nil {
-		t.Fatal("expected --engine flag")
-	}
-	if cmd.Flags().Lookup("visibility").DefValue != "private" {
-		t.Fatalf("unexpected visibility default: %s", cmd.Flags().Lookup("visibility").DefValue)
-	}
-	if cmd.Flags().Lookup("require-owner-type").DefValue != "any" {
-		t.Fatalf("unexpected require-owner-type default: %s", cmd.Flags().Lookup("require-owner-type").DefValue)
-	}
-	if cmd.GroupID != "" {
-		t.Fatalf("group should be assigned by main, got %q", cmd.GroupID)
-	}
-}
-
-func TestNewBootstrapCommand_RequiresRepoFlagOnExecute(t *testing.T) {
-	cmd := NewBootstrapCommand(func(string) error { return nil })
-	cmd.SetArgs([]string{})
-	err := cmd.Execute()
-	if err == nil {
-		t.Fatal("expected missing --repo error")
-	}
-	if err.Error() != "--repo is required. Example: bootstrap --repo github/gh-aw\n\nRun 'bootstrap --help' for usage information" {
-		t.Fatalf("unexpected error: %v", err)
-	}
-}
-
-func TestBuildBootstrapPlan_AttachedCheckoutNeedsInit(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	plan, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:             "octo/platform-ops",
-		Dir:              repoDir,
-		Visibility:       "private",
-		RequireOwnerType: "any",
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("buildBootstrapPlan returned error: %v", err)
-	}
-	if !plan.AttachedCheckout {
-		t.Fatal("expected attached checkout")
-	}
-	if plan.CloneRepo {
-		t.Fatal("did not expect clone plan")
-	}
-	if !plan.InitNeeded {
-		t.Fatal("expected init to be needed")
-	}
-	if len(plan.InitMissingMarkers) == 0 {
-		t.Fatal("expected missing init markers")
-	}
-}
-
-func TestBuildBootstrapPlan_EnforcesOwnerTypeRequirement(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	_, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:             "octo/platform-ops",
-		Dir:              repoDir,
-		RequireOwnerType: "user",
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			ownerType:          func(context.Context, string) (string, error) { return "Organization", nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-	}, repoDir)
-	if err == nil {
-		t.Fatal("expected owner type mismatch error")
-	}
-	if err.Error() != "owner octo is org, but --require-owner-type=user was requested" {
-		t.Fatalf("unexpected error: %v", err)
-	}
-}
-
-func TestBuildBootstrapPlan_WithBootstrapProfileNeedsAction(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	plan, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:    "octo/platform-ops",
-		Dir:     repoDir,
-		Sources: []string{"github/central-agentic-ops"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) {
-			return &resolvedBootstrapProfile{
-				PackageID: "github/central-agentic-ops",
-				Profile: &repositoryPackageBootstrap{
-					Config: []repositoryPackageBootstrapAction{{Type: "repo-variable", Name: "CENTRAL_AGENTIC_OPS_MODE"}},
-				},
-			}, nil
-		},
-		profileNeedsPlan: func(context.Context, string, *resolvedBootstrapProfile, []string, bool) (bool, []string, error) {
-			return true, []string{"- bootstrap profile will configure repository variable CENTRAL_AGENTIC_OPS_MODE"}, nil
-		},
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("buildBootstrapPlan returned error: %v", err)
-	}
-	if !plan.ProfileNeedsAction {
-		t.Fatal("expected bootstrap profile action to require mutation")
-	}
-	if !plan.NeedsMutation {
-		t.Fatal("expected bootstrap profile action to contribute to overall mutation state")
-	}
-	if !slices.Contains(plan.PlanLines, "- evaluate bootstrap actions from github/central-agentic-ops") {
-		t.Fatalf("expected bootstrap profile evaluation line, got %#v", plan.PlanLines)
-	}
-	if !slices.Contains(plan.PlanLines, "- apply bootstrap profile actions (1 action(s))") {
-		t.Fatalf("expected bootstrap profile action line, got %#v", plan.PlanLines)
-	}
-	if !slices.Contains(plan.PlanLines, "- bootstrap profile will configure repository variable CENTRAL_AGENTIC_OPS_MODE") {
-		t.Fatalf("expected bootstrap profile detail line, got %#v", plan.PlanLines)
-	}
-}
-
-func TestRunBootstrapWithRuntime_ExecutesBootstrapProfile(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	profileCalls := 0
-	packageDir := filepath.Join(repoDir, "bootstrap-package")
-	err := runBootstrapWithRuntime(normalizeBootstrapOptions(BootstrapOptions{
-		Ctx:     context.Background(),
-		Repo:    "octo/platform-ops",
-		Dir:     repoDir,
-		Yes:     true,
-		Sources: []string{"./bootstrap-package"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		initRepo: func(InitOptions) error { return nil },
-		addWorkflows: func(context.Context, []string, AddOptions) (*AddWorkflowsResult, error) {
-			return &AddWorkflowsResult{}, nil
-		},
-		compileWorkflows: func(context.Context, CompileConfig) ([]*workflow.WorkflowData, error) {
-			return nil, nil
-		},
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) {
-			return &resolvedBootstrapProfile{
-				PackageID: "github/central-agentic-ops",
-				Profile: &repositoryPackageBootstrap{
-					Config: []repositoryPackageBootstrapAction{{Type: "handoff", Message: "Run readiness"}},
-				},
-			}, nil
-		},
-		profileNeedsPlan: func(context.Context, string, *resolvedBootstrapProfile, []string, bool) (bool, []string, error) {
-			return true, nil, nil
-		},
-		executeProfile: func(_ context.Context, config bootstrapProfileRunConfig) error {
-			profileCalls++
-			if len(config.Sources) != 1 || config.Sources[0] != packageDir {
-				t.Fatalf("expected resolved absolute source %q, got %#v", packageDir, config.Sources)
-			}
-			return nil
-		},
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("runBootstrapWithRuntime returned error: %v", err)
-	}
-	if profileCalls != 1 {
-		t.Fatalf("expected bootstrap profile execution, got %d calls", profileCalls)
-	}
-}
-
-func TestBuildBootstrapPlan_CreateRepoProfileValidatesRequireOwnerType(t *testing.T) {
-	originalCheckOwnerType := bootstrapCheckOwnerType
-	t.Cleanup(func() {
-		bootstrapCheckOwnerType = originalCheckOwnerType
-	})
-	bootstrapCheckOwnerType = func(context.Context, string) (string, error) { return "Organization", nil }
-
-	tempDir := testutil.TempDir(t, "bootstrap-*")
-	checkoutDir := filepath.Join(tempDir, "platform-ops")
-
-	_, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:       "my-user/platform-ops",
-		Dir:        checkoutDir,
-		CreateRepo: true,
-		Sources:    []string{"github/central-agentic-ops"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return false, nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) {
-			return &resolvedBootstrapProfile{
-				PackageID: "github/central-agentic-ops",
-				Profile: &repositoryPackageBootstrap{
-					Config: []repositoryPackageBootstrapAction{{Type: "require-owner-type", Value: "user"}},
-				},
-			}, nil
-		},
-	}, tempDir)
-	if err == nil {
-		t.Fatal("expected create-repo bootstrap profile owner type mismatch")
-	}
-	if !strings.Contains(err.Error(), "bootstrap profile requires user") {
-		t.Fatalf("unexpected error: %v", err)
-	}
-}
-
-func TestResolveBootstrapProfileFromSources_IgnoresNestedWorkflowWithoutManifest(t *testing.T) {
-	originalVersion := GetVersion()
-	originalDownload := downloadPackageFileFromGitHubForHost
-	originalDefaultBranch := getRepositoryPackageDefaultBranch
-	originalLatestRelease := getRepositoryPackageLatestRelease
-	t.Cleanup(func() {
-		SetVersionInfo(originalVersion)
-		downloadPackageFileFromGitHubForHost = originalDownload
-		getRepositoryPackageDefaultBranch = originalDefaultBranch
-		getRepositoryPackageLatestRelease = originalLatestRelease
-	})
-	SetVersionInfo("v1.2.3")
-	getRepositoryPackageDefaultBranch = func(repoSlug, host string) (string, error) {
-		return "main", nil
-	}
-	getRepositoryPackageLatestRelease = func(repoSlug, host string) (string, error) {
-		return "", errors.New("no releases found")
-	}
-	downloadPackageFileFromGitHubForHost = func(_ context.Context, owner, repo, path, ref, host string) ([]byte, error) {
-		return nil, createRepositoryPackageNotFoundError(path)
-	}
-
-	profile, err := resolveBootstrapProfileFromSources(context.Background(), []string{"github/central-agentic-ops/readiness/workflows/daily-status"})
-	if err != nil {
-		t.Fatalf("resolveBootstrapProfileFromSources returned error: %v", err)
-	}
-	if profile != nil {
-		t.Fatalf("expected no bootstrap profile, got %#v", profile)
-	}
-}
-
-func TestParseRepositoryPackageManifest_RejectsUnsupportedBootstrapWhen(t *testing.T) {
-	_, _, err := parseRepositoryPackageManifest("aw.yml", []byte(`name: Control Plane
-config:
-  - type: handoff
-    message: run readiness
-    when:
-      variable: MODE
-      equals: prod
-`))
-	if err == nil {
-		t.Fatal("expected unsupported bootstrap when error")
-	}
-	// The strict anyOf schema rejects unknown fields before the extractor runs.
-	// Accept errors that mention "when" in any form.
-	if !strings.Contains(err.Error(), "when") {
-		t.Fatalf("unexpected error: %v", err)
-	}
-}
-
-func TestParseRepositoryPackageManifest_GitHubAppFields(t *testing.T) {
-	manifest, _, err := parseRepositoryPackageManifest("aw.yml", []byte(`name: Control Plane
-config:
-  - type: github-app
-    app-id-variable: APP_ID
-    private-key-secret: APP_PRIVATE_KEY
-    app-name: Control Plane Bootstrap
-    existing-only: true
-`))
-	if err != nil {
-		t.Fatalf("parseRepositoryPackageManifest returned error: %v", err)
-	}
-	if manifest.Bootstrap == nil || len(manifest.Bootstrap.Config) != 1 {
-		t.Fatalf("expected one bootstrap action, got %#v", manifest.Bootstrap)
-	}
-	action := manifest.Bootstrap.Config[0]
-	if action.AppName != "Control Plane Bootstrap" {
-		t.Fatalf("expected app-name to populate AppName, got %q", action.AppName)
-	}
-	if action.Mode != "existing" {
-		t.Fatalf("expected existing-only to map to existing mode, got %q", action.Mode)
-	}
-}
-
-func TestParseRepositoryPackageManifest_GitHubAppLegacyNameBackfillsAppName(t *testing.T) {
-	manifest, _, err := parseRepositoryPackageManifest("aw.yml", []byte(`name: Control Plane
-config:
-  - type: github-app
-    name: Legacy Bootstrap App
-    app-id-variable: APP_ID
-    private-key-secret: APP_PRIVATE_KEY
-`))
-	if err != nil {
-		t.Fatalf("parseRepositoryPackageManifest returned error: %v", err)
-	}
-	action := manifest.Bootstrap.Config[0]
-	if action.AppName != "Legacy Bootstrap App" {
-		t.Fatalf("expected legacy name to backfill AppName, got %q", action.AppName)
-	}
-}
-
-func TestNormalizeBootstrapRuntime_SetsDefaultProfileHooks(t *testing.T) {
-	normalizedRuntime := normalizeBootstrapRuntime(bootstrapRuntime{})
-	if normalizedRuntime.resolveProfile == nil {
-		t.Fatal("expected resolveProfile default")
-	}
-	if normalizedRuntime.profileNeedsPlan == nil {
-		t.Fatal("expected profileNeedsPlan default")
-	}
-	if normalizedRuntime.executeProfile == nil {
-		t.Fatal("expected executeProfile default")
-	}
-}
-
-func TestResolveBootstrapProfileFromSources(t *testing.T) {
-	originalVersion := GetVersion()
-	originalDownload := downloadPackageFileFromGitHubForHost
-	originalList := listPackageWorkflowFilesForHost
-	originalDirFiles := listPackageDirFilesForHost
-	originalDirSubdirs := listPackageDirSubdirsForHost
-	originalDefaultBranch := getRepositoryPackageDefaultBranch
-	originalLatestRelease := getRepositoryPackageLatestRelease
-	t.Cleanup(func() {
-		SetVersionInfo(originalVersion)
-		downloadPackageFileFromGitHubForHost = originalDownload
-		listPackageWorkflowFilesForHost = originalList
-		listPackageDirFilesForHost = originalDirFiles
-		listPackageDirSubdirsForHost = originalDirSubdirs
-		getRepositoryPackageDefaultBranch = originalDefaultBranch
-		getRepositoryPackageLatestRelease = originalLatestRelease
-	})
-	SetVersionInfo("v1.2.3")
-	getRepositoryPackageDefaultBranch = func(repoSlug, host string) (string, error) {
-		return "main", nil
-	}
-	getRepositoryPackageLatestRelease = func(repoSlug, host string) (string, error) {
-		return "", errors.New("no releases found")
-	}
-	listPackageDirFilesForHost = func(_ context.Context, owner, repo, ref, dirPath, host string) ([]string, error) {
-		return nil, createRepositoryPackageNotFoundError(dirPath)
-	}
-	listPackageDirSubdirsForHost = func(_ context.Context, owner, repo, ref, dirPath, host string) ([]string, error) {
-		return nil, createRepositoryPackageNotFoundError(dirPath)
-	}
-	listPackageWorkflowFilesForHost = func(_ context.Context, owner, repo, ref, workflowPath, host string) ([]string, error) {
-		switch workflowPath {
-		case "workflows", "readiness/workflows":
-			return []string{"workflows/readiness.md"}, nil
-		case ".github/workflows", "readiness/.github/workflows":
-			return nil, createRepositoryPackageNotFoundError(workflowPath)
-		default:
-			return nil, errors.New("unexpected workflow path")
-		}
-	}
-
-	t.Run("returns package bootstrap profile", func(t *testing.T) {
-		downloadPackageFileFromGitHubForHost = func(_ context.Context, owner, repo, path, ref, host string) ([]byte, error) {
-			switch path {
-			case "aw.yml":
-				return []byte("name: Control Plane\nconfig:\n  - type: handoff\n    message: Run readiness\n"), nil
-			case "README.md":
-				return []byte("# Control Plane\n"), nil
-			default:
-				return nil, createRepositoryPackageNotFoundError(path)
-			}
-		}
-
-		profile, err := resolveBootstrapProfileFromSources(context.Background(), []string{"github/central-agentic-ops"})
-		if err != nil {
-			t.Fatalf("resolveBootstrapProfileFromSources returned error: %v", err)
-		}
-		if profile == nil {
-			t.Fatal("expected bootstrap profile")
-		}
-		if profile.PackageID != "github/central-agentic-ops" {
-			t.Fatalf("unexpected package id: %s", profile.PackageID)
-		}
-		if len(profile.Profile.Config) != 1 {
-			t.Fatalf("unexpected action count: %d", len(profile.Profile.Config))
-		}
-	})
-
-	t.Run("returns local package bootstrap profile", func(t *testing.T) {
-		packageDir := t.TempDir()
-		manifestPath := filepath.Join(packageDir, "aw.yml")
-		manifest := []byte("name: Control Plane\nconfig:\n  - type: handoff\n    message: Run readiness\n")
-		if err := os.WriteFile(manifestPath, manifest, 0o644); err != nil {
-			t.Fatalf("write manifest: %v", err)
-		}
-
-		profile, err := resolveBootstrapProfileFromSources(context.Background(), []string{packageDir})
-		if err != nil {
-			t.Fatalf("resolveBootstrapProfileFromSources returned error: %v", err)
-		}
-		if profile == nil {
-			t.Fatal("expected bootstrap profile")
-		}
-		if profile.Source != packageDir {
-			t.Fatalf("unexpected source: %s", profile.Source)
-		}
-		if profile.PackageID != filepath.Clean(packageDir) {
-			t.Fatalf("unexpected package id: %s", profile.PackageID)
-		}
-		if len(profile.Profile.Config) != 1 {
-			t.Fatalf("unexpected action count: %d", len(profile.Profile.Config))
-		}
-	})
-
-	t.Run("rejects multiple package bootstrap profiles", func(t *testing.T) {
-		downloadPackageFileFromGitHubForHost = func(_ context.Context, owner, repo, path, ref, host string) ([]byte, error) {
-			switch path {
-			case "aw.yml":
-				return []byte("name: Root\nconfig:\n  - type: handoff\n    message: one\n"), nil
-			case "readiness/aw.yml":
-				return []byte("name: Readiness\nconfig:\n  - type: handoff\n    message: two\n"), nil
-			case "README.md", "readiness/README.md":
-				return []byte("# Package\n"), nil
-			default:
-				return nil, createRepositoryPackageNotFoundError(path)
-			}
-		}
-
-		_, err := resolveBootstrapProfileFromSources(context.Background(), []string{"github/central-agentic-ops", "github/central-agentic-ops/readiness"})
-		if err == nil {
-			t.Fatal("expected multiple profile error")
-		}
-		if !strings.Contains(err.Error(), "multiple bootstrap profiles matched") {
-			t.Fatalf("unexpected error: %v", err)
-		}
-	})
-}
-
-func TestBuildBootstrapPlan_CreateRepoProfileDoesNotAssumeRepoExists(t *testing.T) {
-	t.Parallel()
-
-	tempDir := testutil.TempDir(t, "bootstrap-*")
-	checkoutDir := filepath.Join(tempDir, "platform-ops")
-	var repoReady bool
-
-	plan, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:       "my-mona-org/platform-ops",
-		Dir:        checkoutDir,
-		CreateRepo: true,
-		Sources:    []string{"github/central-agentic-ops"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return false, nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) {
-			return &resolvedBootstrapProfile{
-				PackageID: "github/central-agentic-ops",
-				Profile: &repositoryPackageBootstrap{
-					Config: []repositoryPackageBootstrapAction{{Type: "repo-variable", Name: "CENTRAL_AGENTIC_OPS_MODE"}},
-				},
-			}, nil
-		},
-		profileNeedsPlan: func(_ context.Context, _ string, _ *resolvedBootstrapProfile, _ []string, ready bool) (bool, []string, error) {
-			repoReady = ready
-			return true, []string{"- bootstrap profile will configure repository variable CENTRAL_AGENTIC_OPS_MODE"}, nil
-		},
-	}, tempDir)
-	if err != nil {
-		t.Fatalf("buildBootstrapPlan returned error: %v", err)
-	}
-	if repoReady {
-		t.Fatal("expected create-repo plan to treat bootstrap profile state as not yet queryable")
-	}
-	if !plan.ProfileNeedsAction {
-		t.Fatal("expected bootstrap profile action to require mutation")
-	}
-}
-
-func TestRunBootstrapWithRuntime_CreateCloneInitAddCompile(t *testing.T) {
-	tempDir := testutil.TempDir(t, "bootstrap-*")
-	checkoutDir := filepath.Join(tempDir, "platform-ops")
-
-	createCalls := 0
-	cloneCalls := 0
-	initCalls := 0
-	addCalls := 0
-	compileCalls := 0
-
-	err := runBootstrapWithRuntime(normalizeBootstrapOptions(BootstrapOptions{
-		Ctx:        context.Background(),
-		Repo:       "octo/platform-ops",
-		Dir:        checkoutDir,
-		CreateRepo: true,
-		Yes:        true,
-		Sources:    []string{"github/central-agentic-ops/readiness"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:  func(context.Context) error { return nil },
-			repoExists: func(context.Context, string) (bool, error) { return false, nil },
-			createRepo: func(context.Context, string, string) error {
-				createCalls++
-				return nil
-			},
-			cloneRepo: func(_ context.Context, _ string, dir string) error {
-				cloneCalls++
-				return os.MkdirAll(dir, 0o755)
-			},
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		confirmAction:  func(string, string, string) (bool, error) { return false, nil },
-		initRepo:       func(InitOptions) error { initCalls++; return nil },
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) { return nil, nil },
-		addWorkflows: func(context.Context, []string, AddOptions) (*AddWorkflowsResult, error) {
-			addCalls++
-			return &AddWorkflowsResult{}, nil
-		},
-		compileWorkflows: func(context.Context, CompileConfig) ([]*workflow.WorkflowData, error) {
-			compileCalls++
-			return nil, nil
-		},
-	}, tempDir)
-	if err != nil {
-		t.Fatalf("runBootstrapWithRuntime returned error: %v", err)
-	}
-	if createCalls != 1 {
-		t.Fatalf("expected 1 create call, got %d", createCalls)
-	}
-	if cloneCalls != 1 {
-		t.Fatalf("expected 1 clone call, got %d", cloneCalls)
-	}
-	if initCalls != 1 {
-		t.Fatalf("expected 1 init call, got %d", initCalls)
-	}
-	if addCalls != 1 {
-		t.Fatalf("expected 1 add call, got %d", addCalls)
-	}
-	if compileCalls != 1 {
-		t.Fatalf("expected 1 compile call, got %d", compileCalls)
-	}
-}
-
-func TestRunBootstrapWithRuntime_RequiresYesInCIWhenMutationPending(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	t.Setenv("CI", "true")
-
-	confirmCalls := 0
-	err := runBootstrapWithRuntime(normalizeBootstrapOptions(BootstrapOptions{
-		Ctx:  context.Background(),
-		Repo: "octo/platform-ops",
-		Dir:  repoDir,
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		confirmAction: func(string, string, string) (bool, error) {
-			confirmCalls++
-			return true, nil
-		},
-	}, repoDir)
-	if err == nil {
-		t.Fatal("expected CI confirmation error")
-	}
-	if err.Error() != "--yes is required in CI when bootstrap would make changes. Example: gh aw bootstrap --repo OWNER/REPO --yes" {
-		t.Fatalf("unexpected error: %v", err)
-	}
-	if confirmCalls != 0 {
-		t.Fatalf("confirmAction should not be called in CI, got %d calls", confirmCalls)
-	}
-}
-
-func TestRunBootstrapWithRuntime_PropagatesCleanWorktreeError(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	wantErr := errors.New("working directory has uncommitted changes, please commit or stash them first")
-
-	err := runBootstrapWithRuntime(normalizeBootstrapOptions(BootstrapOptions{
-		Ctx:  context.Background(),
-		Repo: "octo/platform-ops",
-		Dir:  repoDir,
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:     func(context.Context) error { return nil },
-			repoExists:    func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo: func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error {
-				return wantErr
-			},
-		},
-	}, repoDir)
-	if !errors.Is(err, wantErr) {
-		t.Fatalf("expected clean worktree error, got %v", err)
-	}
-}
-
-func TestRunBootstrapWithRuntime_AddWorkflowFailureAfterInitIncludesRecoveryHint(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	addErr := errors.New("add failed")
-	initCalled := false
-
-	err := runBootstrapWithRuntime(normalizeBootstrapOptions(BootstrapOptions{
-		Ctx:     context.Background(),
-		Repo:    "octo/platform-ops",
-		Dir:     repoDir,
-		Yes:     true,
-		Sources: []string{"github/central-agentic-ops/readiness"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		initRepo:       func(InitOptions) error { initCalled = true; return nil },
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) { return nil, nil },
-		addWorkflows: func(context.Context, []string, AddOptions) (*AddWorkflowsResult, error) {
-			return nil, addErr
-		},
-	}, repoDir)
-	if err == nil {
-		t.Fatal("expected add workflow error")
-	}
-	if !strings.Contains(err.Error(), bootstrapAddWorkflowsRetryHint) {
-		t.Fatalf("expected recovery hint in error, got %v", err)
-	}
-	if !errors.Is(err, addErr) {
-		t.Fatalf("expected wrapped add error, got %v", err)
-	}
-	if !initCalled {
-		t.Fatal("expected repository initialization to run before add failure")
-	}
-}
-
-func TestBuildBootstrapPlan_PlanOnlySkipsCleanWorktreeCheck(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	wantErr := errors.New("working directory has uncommitted changes, please commit or stash them first")
-
-	_, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:     "octo/platform-ops",
-		Dir:      repoDir,
-		PlanOnly: true,
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:     func(context.Context) error { return nil },
-			repoExists:    func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo: func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error {
-				return wantErr
-			},
-		},
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("expected plan-only run to ignore clean worktree checks, got %v", err)
-	}
-}
-
-func TestBuildBootstrapPlan_RejectsNonExistentNestedCheckoutPath(t *testing.T) {
-	parentRepoDir := initBootstrapGitRepo(t)
-	nestedDir := filepath.Join(parentRepoDir, "new-checkout")
-
-	_, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo: "octo/platform-ops",
-		Dir:  nestedDir,
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:  func(context.Context) error { return nil },
-			repoExists: func(context.Context, string) (bool, error) { return true, nil },
-		},
-	}, parentRepoDir)
-	if err == nil {
-		t.Fatal("expected nested checkout path validation error")
-	}
-	if !strings.Contains(err.Error(), "is inside a different git checkout rooted at") {
-		t.Fatalf("unexpected error: %v", err)
-	}
-	if !strings.Contains(err.Error(), parentRepoDir) {
-		t.Fatalf("expected error to include checkout root %s, got %v", parentRepoDir, err)
-	}
-}
-
-func TestRunBootstrapWithRuntime_SkipsExistingSourcedWorkflow(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	writeBootstrapMarkers(t, repoDir, "")
-	workflowPath := filepath.Join(repoDir, ".github", "workflows", "readiness.md")
-	if err := os.MkdirAll(filepath.Dir(workflowPath), 0o755); err != nil {
-		t.Fatalf("failed to create workflow dir: %v", err)
-	}
-	content := "---\nsource: github/central-agentic-ops/readiness@main\n---\n\n# Readiness\n"
-	if err := os.WriteFile(workflowPath, []byte(content), 0o644); err != nil {
-		t.Fatalf("failed to write workflow: %v", err)
-	}
-
-	plan, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:    "octo/platform-ops",
-		Dir:     repoDir,
-		Sources: []string{"github/central-agentic-ops/readiness"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) { return nil, nil },
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("buildBootstrapPlan returned error: %v", err)
-	}
-	if plan.NeedsMutation {
-		t.Fatal("expected no-op bootstrap plan when sourced workflow is already present")
-	}
-	if len(plan.ResolvedSources) != 0 {
-		t.Fatalf("expected no pending sources, got %d", len(plan.ResolvedSources))
-	}
-	if len(plan.SkippedSources) != 1 || plan.SkippedSources[0] != "readiness" {
-		t.Fatalf("expected skipped readiness workflow, got %#v", plan.SkippedSources)
-	}
-
-	initCalls := 0
-	addCalls := 0
-	compileCalls := 0
-
-	err = runBootstrapWithRuntime(normalizeBootstrapOptions(BootstrapOptions{
-		Ctx:     context.Background(),
-		Repo:    "octo/platform-ops",
-		Dir:     repoDir,
-		Yes:     true,
-		Sources: []string{"github/central-agentic-ops/readiness"},
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-		initRepo:       func(InitOptions) error { initCalls++; return nil },
-		resolveProfile: func(context.Context, []string) (*resolvedBootstrapProfile, error) { return nil, nil },
-		addWorkflows: func(context.Context, []string, AddOptions) (*AddWorkflowsResult, error) {
-			addCalls++
-			return &AddWorkflowsResult{}, nil
-		},
-		compileWorkflows: func(context.Context, CompileConfig) ([]*workflow.WorkflowData, error) {
-			compileCalls++
-			return nil, nil
-		},
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("runBootstrapWithRuntime returned error: %v", err)
-	}
-	if initCalls != 0 {
-		t.Fatalf("expected init to be skipped, got %d calls", initCalls)
-	}
-	if addCalls != 0 {
-		t.Fatalf("expected add to be skipped, got %d calls", addCalls)
-	}
-	if compileCalls != 0 {
-		t.Fatalf("expected compile to be skipped, got %d calls", compileCalls)
-	}
-}
-
-func TestBuildBootstrapPlan_ForceKeepsExistingSourcedWorkflow(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	writeBootstrapMarkers(t, repoDir, "")
-	workflowPath := filepath.Join(repoDir, ".github", "workflows", "readiness.md")
-	if err := os.MkdirAll(filepath.Dir(workflowPath), 0o755); err != nil {
-		t.Fatalf("failed to create workflow dir: %v", err)
-	}
-	content := "---\nsource: github/central-agentic-ops/readiness@main\n---\n\n# Readiness\n"
-	if err := os.WriteFile(workflowPath, []byte(content), 0o644); err != nil {
-		t.Fatalf("failed to write workflow: %v", err)
-	}
-
-	plan, err := buildBootstrapPlan(context.Background(), normalizeBootstrapOptions(BootstrapOptions{
-		Repo:    "octo/platform-ops",
-		Dir:     repoDir,
-		Sources: []string{"github/central-agentic-ops/readiness"},
-		Force:   true,
-	}), bootstrapRuntime{
-		setupRepositoryRuntime: setupRepositoryRuntime{
-			checkAuth:          func(context.Context) error { return nil },
-			repoExists:         func(context.Context, string) (bool, error) { return true, nil },
-			dirOriginRepo:      func(string) (string, error) { return "octo/platform-ops", nil },
-			checkCleanWorktree: func(bool) error { return nil },
-		},
-	}, repoDir)
-	if err != nil {
-		t.Fatalf("buildBootstrapPlan returned error: %v", err)
-	}
-	if !plan.NeedsMutation {
-		t.Fatal("expected force plan to keep sourced workflow in mutation set")
-	}
-	if len(plan.ResolvedSources) != 1 || plan.ResolvedSources[0] != "github/central-agentic-ops/readiness" {
-		t.Fatalf("expected readiness source to be preserved with --force, got %#v", plan.ResolvedSources)
-	}
-	if len(plan.SkippedSources) != 0 {
-		t.Fatalf("did not expect skipped sources with --force, got %#v", plan.SkippedSources)
-	}
-}
-
-func TestValidateBootstrapOptions_RejectsEmptyRepoComponents(t *testing.T) {
-	tests := []BootstrapOptions{
-		{Repo: "/repo"},
-		{Repo: "owner/"},
-	}
-
-	for _, tt := range tests {
-		if err := validateBootstrapOptions(tt); err == nil {
-			t.Fatalf("expected invalid repo slug error for %q", tt.Repo)
-		}
-	}
-}
-
-func TestMissingBootstrapInitMarkers_DetectsInvalidArtifacts(t *testing.T) {
-	repoDir := initBootstrapGitRepo(t)
-	writeBootstrapMarkers(t, repoDir, "")
-
-	if err := os.WriteFile(filepath.Join(repoDir, ".gitattributes"), []byte(""), 0o644); err != nil {
-		t.Fatalf("failed to write .gitattributes: %v", err)
-	}
-	if err := os.WriteFile(filepath.Join(repoDir, ".github", "mcp.json"), []byte("{invalid"), 0o644); err != nil {
-		t.Fatalf("failed to write .github/mcp.json: %v", err)
-	}
-
-	missing, err := missingBootstrapInitMarkers(repoDir, "")
-	if err != nil {
-		t.Fatalf("missingBootstrapInitMarkers returned error: %v", err)
-	}
-	if !slices.Contains(missing, ".gitattributes") {
-		t.Fatalf("expected .gitattributes to be marked missing, got %#v", missing)
-	}
-	if !slices.Contains(missing, ".github/mcp.json") {
-		t.Fatalf("expected .github/mcp.json to be marked missing, got %#v", missing)
-	}
-}
-
-func initBootstrapGitRepo(t *testing.T) string {
-	t.Helper()
-	repoDir := testutil.TempDir(t, "bootstrap-repo-*")
-	cmd := exec.Command("git", "init", repoDir)
-	if output, err := cmd.CombinedOutput(); err != nil {
-		t.Skipf("git not available: %v (%s)", err, output)
-	}
-	return repoDir
-}
-
-func writeBootstrapMarkers(t *testing.T, repoDir string, engineOverride string) {
-	t.Helper()
-	for _, marker := range expectedBootstrapInitMarkers(engineOverride) {
-		path := filepath.Join(repoDir, filepath.FromSlash(marker))
-		if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
-			t.Fatalf("failed to create marker dir for %s: %v", marker, err)
-		}
-		content, err := bootstrapMarkerContent(marker, repoDir)
-		if err != nil {
-			t.Fatalf("failed to render marker content for %s: %v", marker, err)
-		}
-		if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
-			t.Fatalf("failed to create marker %s: %v", marker, err)
-		}
-	}
-}
-
-func bootstrapMarkerContent(marker string, repoDir string) (string, error) {
-	switch marker {
-	case ".gitattributes":
-		return constants.WorkflowsLockYmlGitAttributesEntry + "\n", nil
-	case ".vscode/settings.json":
-		return "{\n  \"github.copilot.chat.agent.thinkingTool\": true\n}\n", nil
-	case ".github/skills/agentic-workflows/SKILL.md":
-		return buildAgenticWorkflowsSkillContent()
-	case ".github/agents/agentic-workflows.md":
-		return buildAgenticWorkflowsAgentContent(repoDir)
-	case ".github/mcp.json":
-		return "{\n  \"mcpServers\": {\n    \"github-agentic-workflows\": {\n      \"type\": \"local\",\n      \"command\": \"gh\",\n      \"args\": [\"aw\", \"mcp-server\"],\n      \"tools\": [\"compile\"]\n    }\n  }\n}\n", nil
-	case ".github/workflows/copilot-setup-steps.yml":
-		return "name: Copilot Setup Steps\njobs:\n  copilot-setup-steps:\n    steps:\n      - uses: actions/setup-cli@v1\n", nil
-	default:
-		return "ok\n", nil
-	}
-}
diff --git a/pkg/cli/bootstrap_test_helpers_test.go b/pkg/cli/bootstrap_test_helpers_test.go
new file mode 100644
index 00000000000..7900f621e5e
--- /dev/null
+++ b/pkg/cli/bootstrap_test_helpers_test.go
@@ -0,0 +1,21 @@
+//go:build !integration
+
+package cli
+
+import (
+	"os/exec"
+	"testing"
+)
+
+func initBootstrapGitRepo(t *testing.T) string {
+	t.Helper()
+
+	repoDir := t.TempDir()
+	cmd := exec.Command("git", "init")
+	cmd.Dir = repoDir
+	if output, err := cmd.CombinedOutput(); err != nil {
+		t.Fatalf("git init failed: %v\n%s", err, string(output))
+	}
+
+	return repoDir
+}
diff --git a/pkg/cli/dispatch.go b/pkg/cli/dispatch.go
index ae4b3d94c87..50d4341c998 100644
--- a/pkg/cli/dispatch.go
+++ b/pkg/cli/dispatch.go
@@ -250,11 +250,26 @@ func fetchAndSaveRemoteDispatchWorkflows(ctx context.Context, content string, sp
 				tracker.TrackCreated(targetPath)
 			}
 		}
+
+		fetchDownloadedWorkflowFrontmatterImports(ctx, workflowContent, spec, remoteFilePath, targetDir, verbose, force, tracker)
 	}
 
 	return nil
 }
 
+func fetchDownloadedWorkflowFrontmatterImports(ctx context.Context, workflowContent []byte, parentSpec *WorkflowSpec, remoteFilePath, targetDir string, verbose bool, force bool, tracker *FileTracker) {
+	depSpec := &WorkflowSpec{
+		RepoSpec: RepoSpec{
+			RepoSlug: parentSpec.RepoSlug,
+			Version:  parentSpec.Version,
+		},
+		WorkflowPath: remoteFilePath,
+	}
+	if err := fetchAndSaveRemoteFrontmatterImports(ctx, string(workflowContent), depSpec, targetDir, verbose, force, tracker); err != nil && verbose {
+		fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to fetch frontmatter imports for %s: %v", remoteFilePath, err)))
+	}
+}
+
 // fetchAndSaveDispatchWorkflowsFromParsedFile parses a locally-saved workflow file to obtain
 // the fully merged safe-outputs configuration (including dispatch workflows that originate
 // from imported shared workflows), then fetches any referenced dispatch workflow files that
@@ -447,5 +462,7 @@ func fetchAndSaveDispatchWorkflowsFromParsedFile(ctx context.Context, destFile s
 				tracker.TrackCreated(targetPath)
 			}
 		}
+
+		fetchDownloadedWorkflowFrontmatterImports(ctx, workflowContent, spec, remoteFilePath, targetDir, verbose, force, tracker)
 	}
 }
diff --git a/pkg/cli/includes.go b/pkg/cli/includes.go
index c9ee684f39f..8dbb2a6e772 100644
--- a/pkg/cli/includes.go
+++ b/pkg/cli/includes.go
@@ -21,6 +21,7 @@ import (
 
 // includeDirectivePattern matches @include or @include? directives with their path argument
 var includeDirectivePattern = regexp.MustCompile(`^@include(\?)?\s+(.+)$`)
+var downloadRemoteImportFile = parser.DownloadFileFromGitHub
 
 // FetchIncludeFromSource fetches an include file from GitHub directly using a workflowspec format path.
 // The includePath should be in the format: owner/repo/path/to/file.md[@ref]
@@ -387,7 +388,7 @@ func fetchFrontmatterImportsRecursive(ctx context.Context, content, currentBaseD
 		// Download from the source repository
 		downloadFn := opts.downloadFn
 		if downloadFn == nil {
-			downloadFn = parser.DownloadFileFromGitHub
+			downloadFn = downloadRemoteImportFile
 		}
 		importContent, err := downloadFn(ctx, opts.owner, opts.repo, remoteFilePath, opts.ref)
 		if err != nil {
diff --git a/pkg/cli/remote_workflow_test.go b/pkg/cli/remote_workflow_test.go
index 8a4a1364cbe..a470d153e83 100644
--- a/pkg/cli/remote_workflow_test.go
+++ b/pkg/cli/remote_workflow_test.go
@@ -1893,6 +1893,59 @@ safe-outputs:
 	assert.NoError(t, err, "force=true should bypass conflict detection and return nil (download fails silently)")
 }
 
+func TestFetchAndSaveRemoteDispatchWorkflows_FetchesNestedFrontmatterImports(t *testing.T) {
+	dir := t.TempDir()
+	originalDownloadRemoteImportFile := downloadRemoteImportFile
+	t.Cleanup(func() {
+		downloadRemoteImportFile = originalDownloadRemoteImportFile
+	})
+
+	content := `---
+safe-outputs:
+  dispatch-workflow:
+    workflows:
+      - dependent-workflow
+---
+# Main
+`
+	spec := &WorkflowSpec{
+		RepoSpec:     RepoSpec{RepoSlug: "github/gh-aw", Version: "main"},
+		WorkflowPath: ".github/workflows/main.md",
+	}
+
+	mockDownloader := func(_ context.Context, _, _, filePath, _ string) ([]byte, error) {
+		switch filePath {
+		case ".github/workflows/dependent-workflow.md":
+			return []byte(`---
+imports:
+  - uses: shared/helper.md
+---
+# Dependent
+`), nil
+		default:
+			return nil, errors.New("unexpected workflow path: " + filePath)
+		}
+	}
+
+	downloadRemoteImportFile = func(_ context.Context, owner, repo, filePath, ref string) ([]byte, error) {
+		if owner != "github" || repo != "gh-aw" || ref != "main" {
+			return nil, errors.New("unexpected import coordinates")
+		}
+		if filePath == ".github/workflows/shared/helper.md" {
+			return []byte("---\n# Helper\n"), nil
+		}
+		return nil, errors.New("unexpected import path: " + filePath)
+	}
+
+	err := fetchAndSaveRemoteDispatchWorkflows(context.Background(), content, spec, dir, false, false, nil, mockDownloader)
+	require.NoError(t, err)
+
+	_, err = os.Stat(filepath.Join(dir, "dependent-workflow.md"))
+	require.NoError(t, err)
+	_, err = os.Stat(filepath.Join(dir, "shared", "helper.md"))
+	require.NoError(t, err)
+}
+
 // ---------------------------------------------------------------------------
 // fetchAndSaveRemoteResources — conflict detection
 // ---------------------------------------------------------------------------
diff --git a/pkg/cli/setup_repository.go b/pkg/cli/setup_repository.go
index 54349921e09..2ce26728943 100644
--- a/pkg/cli/setup_repository.go
+++ b/pkg/cli/setup_repository.go
@@ -48,8 +48,8 @@ type SetupRepositoryCheckResult struct {
 }
 
 // setupRepositoryRuntime holds the reusable repository/auth setup primitives that
-// higher-level setup flows can compose. bootstrap is the first consumer, but the
-// helpers are intentionally generic so future auth/setup commands can reuse them.
+// higher-level setup flows can compose. The helpers are intentionally generic so
+// future auth/setup commands can reuse them.
 type setupRepositoryRuntime struct {
 	checkAuth          func(context.Context) error
 	repoExists         func(context.Context, string) (bool, error)
diff --git a/pkg/parser/schemas/aw_manifest_schema.json b/pkg/parser/schemas/aw_manifest_schema.json
index 91e211dbd22..af4835bd30c 100644
--- a/pkg/parser/schemas/aw_manifest_schema.json
+++ b/pkg/parser/schemas/aw_manifest_schema.json
@@ -485,6 +485,22 @@
               }
             }
           },
+          {
+            "description": "commit-and-push: stage, commit, and push local repository changes",
+            "type": "object",
+            "required": ["type", "message"],
+            "additionalProperties": false,
+            "properties": {
+              "type": {
+                "type": "string",
+                "const": "commit-and-push"
+              },
+              "message": {
+                "type": "string",
+                "minLength": 1
+              }
+            }
+          },
           {
             "description": "handoff: display a message and hand off to the user",
             "type": "object",
diff --git a/pkg/workflow/compiler_orchestrator_workflow_test.go b/pkg/workflow/compiler_orchestrator_workflow_test.go
index b74b0f27a0e..34cf45a2121 100644
--- a/pkg/workflow/compiler_orchestrator_workflow_test.go
+++ b/pkg/workflow/compiler_orchestrator_workflow_test.go
@@ -444,6 +444,24 @@ func TestSetMainWorkflowEnvSources_OnlyTracksPresentKeys(t *testing.T) {
 	}, workflowData.EnvSources)
 }
 
+func TestMergeWorkflowEnv_InlinesImportedEnvReferences(t *testing.T) {
+	compiler := NewCompiler()
+	workflowData := &WorkflowData{}
+	importsResult := &parser.ImportsResult{
+		MergedEnv: `{"REVIEW_OUTPUT_REPO":"${{ github.event.inputs.safe_output_repo || vars.CENTRAL_AGENTIC_OPS_REVIEW_REPO || '' }}","SAFE_OUTPUT_REPO":"${{ (github.event.inputs.safe_output_mode || vars.CENTRAL_AGENTIC_OPS_MODE || 'preview') == 'review' && env.REVIEW_OUTPUT_REPO || '' }}"}`,
+		MergedEnvSources: map[string]string{
+			"REVIEW_OUTPUT_REPO": "shared/control.md",
+			"SAFE_OUTPUT_REPO":   "shared/control.md",
+		},
+	}
+
+	err := compiler.mergeWorkflowEnv(map[string]any{}, workflowData, importsResult)
+	require.NoError(t, err)
+	assert.Contains(t, workflowData.Env, "SAFE_OUTPUT_REPO: ${{ (github.event.inputs.safe_output_mode || vars.CENTRAL_AGENTIC_OPS_MODE || 'preview') == 'review' && (github.event.inputs.safe_output_repo || vars.CENTRAL_AGENTIC_OPS_REVIEW_REPO || '') || '' }}")
+	assert.NotContains(t, workflowData.Env, "env.REVIEW_OUTPUT_REPO")
+	assert.Equal(t, "shared/control.md", workflowData.EnvSources["SAFE_OUTPUT_REPO"])
+}
+
 // TestProcessAndMergeSteps_NoSteps tests processAndMergeSteps with no steps
 func TestProcessAndMergeSteps_NoSteps(t *testing.T) {
 	compiler := NewCompiler()
diff --git a/pkg/workflow/imports.go b/pkg/workflow/imports.go
index d8707007112..750bec1e96a 100644
--- a/pkg/workflow/imports.go
+++ b/pkg/workflow/imports.go
@@ -628,7 +628,121 @@ func mergeEnv(topEnv map[string]any, importedEnvJSON string) (map[string]any, er
 
 	// Top-level env vars take precedence: copy last so they override any imported values
 	maps.Copy(result, topEnv)
+	if err := normalizeWorkflowEnvReferences(result); err != nil {
+		return nil, err
+	}
 
 	importsLog.Printf("Merged %d total env vars", len(result))
 	return result, nil
 }
+
+func normalizeWorkflowEnvReferences(env map[string]any) error {
+	if len(env) == 0 {
+		return nil
+	}
+
+	resolved := make(map[string]string, len(env))
+	resolving := make(map[string]struct{}, len(env))
+	for key, raw := range env {
+		value, ok := raw.(string)
+		if !ok {
+			continue
+		}
+		normalized, err := resolveWorkflowEnvValue(key, value, env, resolved, resolving)
+		if err != nil {
+			return err
+		}
+		env[key] = normalized
+	}
+	return nil
+}
+
+func resolveWorkflowEnvValue(key, value string, env map[string]any, resolved map[string]string, resolving map[string]struct{}) (string, error) {
+	if normalized, ok := resolved[key]; ok {
+		return normalized, nil
+	}
+	if _, ok := resolving[key]; ok {
+		return "", fmt.Errorf("workflow env %q references itself recursively", key)
+	}
+
+	resolving[key] = struct{}{}
+	defer delete(resolving, key)
+
+	normalized, err := inlineWorkflowEnvReferences(value, env, resolved, resolving)
+	if err != nil {
+		return "", err
+	}
+	resolved[key] = normalized
+	return normalized, nil
+}
+
+func inlineWorkflowEnvReferences(value string, env map[string]any, resolved map[string]string, resolving map[string]struct{}) (string, error) {
+	inner, ok := extractWrappedGitHubExpression(value)
+	if !ok {
+		return value, nil
+	}
+
+	var builder strings.Builder
+	for i := 0; i < len(inner); {
+		if inner[i] == '\'' {
+			next := consumeSingleQuotedGitHubExpressionString(inner, i)
+			builder.WriteString(inner[i:next])
+			i = next
+			continue
+		}
+
+		if !isGitHubExpressionIdentifierStart(inner, i) {
+			builder.WriteByte(inner[i])
+			i++
+			continue
+		}
+
+		start := i
+		for i < len(inner) && isGitHubExpressionIdentifierChar(inner[i]) {
+			i++
+		}
+		if inner[start:i] != "env" || i >= len(inner) || inner[i] != '.' || i+1 >= len(inner) || !isGitHubExpressionIdentifierStart(inner, i+1) {
+			builder.WriteString(inner[start:i])
+			continue
+		}
+
+		refStart := i + 1
+		refEnd := refStart + 1
+		for refEnd < len(inner) && isGitHubExpressionIdentifierChar(inner[refEnd]) {
+			refEnd++
+		}
+
+		replacement, replaced, err := renderWorkflowEnvReferenceValue(inner[refStart:refEnd], env, resolved, resolving)
+		if err != nil {
+			return "", err
+		}
+		if replaced {
+			builder.WriteString(replacement)
+		} else {
+			builder.WriteString(inner[start:refEnd])
+		}
+		i = refEnd
+	}
+
+	return wrapGitHubExpression(builder.String()), nil
+}
+
+func renderWorkflowEnvReferenceValue(name string, env map[string]any, resolved map[string]string, resolving map[string]struct{}) (string, bool, error) {
+	raw, ok := env[name]
+	if !ok {
+		return "", false, nil
+	}
+	value, ok := raw.(string)
+	if !ok {
+		return "", false, nil
+	}
+
+	normalized, err := resolveWorkflowEnvValue(name, value, env, resolved, resolving)
+	if err != nil {
+		return "", false, err
+	}
+	if inner, ok := extractWrappedGitHubExpression(normalized); ok {
+		return "(" + inner + ")", true, nil
+	}
+	return BuildStringLiteral(normalized).Render(), true, nil
+}
diff --git a/pkg/workflow/imports_env_test.go b/pkg/workflow/imports_env_test.go
index f4f16673df2..637edc55dd7 100644
--- a/pkg/workflow/imports_env_test.go
+++ b/pkg/workflow/imports_env_test.go
@@ -79,3 +79,16 @@ func TestMergeEnvWithInvalidJSON(t *testing.T) {
 	require.Error(t, err, "mergeEnv should return an error for invalid JSON")
 	assert.Contains(t, err.Error(), "failed to parse imported env JSON", "Error message should be descriptive")
 }
+
+func TestMergeEnvNormalizesImportedWorkflowEnvReferences(t *testing.T) {
+	importedJSON := `{"CENTRAL_AGENTIC_OPS_MODE":"${{ vars.CENTRAL_AGENTIC_OPS_MODE || '' }}","GH_AW_SAFE_OUTPUT_MODE":"${{ github.event.inputs.safe_output_mode || vars.CENTRAL_AGENTIC_OPS_MODE || 'preview' }}","REVIEW_OUTPUT_REPO":"${{ github.event.inputs.safe_output_repo || vars.CENTRAL_AGENTIC_OPS_REVIEW_REPO || '' }}","SAFE_OUTPUT_REPO":"${{ (github.event.inputs.safe_output_mode || vars.CENTRAL_AGENTIC_OPS_MODE || 'preview') == 'review' && env.REVIEW_OUTPUT_REPO || '' }}"}`
+
+	result, err := mergeEnv(nil, importedJSON)
+	require.NoError(t, err, "mergeEnv should inline references to other merged workflow env vars")
+	assert.Equal(
+		t,
+		"${{ (github.event.inputs.safe_output_mode || vars.CENTRAL_AGENTIC_OPS_MODE || 'preview') == 'review' && (github.event.inputs.safe_output_repo || vars.CENTRAL_AGENTIC_OPS_REVIEW_REPO || '') || '' }}",
+		result["SAFE_OUTPUT_REPO"],
+	)
+	assert.NotContains(t, result["SAFE_OUTPUT_REPO"], "env.REVIEW_OUTPUT_REPO")
+}
