From 223668b02a793b849248861b8b25a0110478db44 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 30 Apr 2026 17:08:28 +0000
Subject: [PATCH 1/2] Initial plan


From be5a457d9f1da7982eb761217f328b5a7a676c28 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 30 Apr 2026 18:00:03 +0000
Subject: [PATCH 2/2] feat: migrate raw fmt.Fprintf/Fprintln(os.Stderr) to
 console.Format* helpers for UX consistency

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/3ddc1a3c-31e4-48fe-a7ab-c4e985ec0c5d

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
---
 pkg/cli/actionlint.go                        |   8 +-
 pkg/cli/add_interactive_engine.go            |   2 +-
 pkg/cli/add_interactive_git.go               |  12 +-
 pkg/cli/add_interactive_orchestrator.go      |  16 +-
 pkg/cli/add_interactive_secrets.go           |   3 +-
 pkg/cli/add_interactive_workflow.go          |  32 ++--
 pkg/cli/audit.go                             |   6 +-
 pkg/cli/audit_cross_run_render.go            |  24 +--
 pkg/cli/audit_report_render.go               |  26 +--
 pkg/cli/audit_report_render_findings.go      |  56 +++---
 pkg/cli/audit_report_render_firewall.go      |  14 +-
 pkg/cli/audit_report_render_guard.go         |  12 +-
 pkg/cli/audit_report_render_overview.go      |  50 +++---
 pkg/cli/audit_report_render_tools.go         |   8 +-
 pkg/cli/compile_file_operations.go           |   2 +-
 pkg/cli/compile_stats.go                     |  12 +-
 pkg/cli/copilot_agents.go                    |   4 +-
 pkg/cli/copilot_setup.go                     |  29 +--
 pkg/cli/deps_report.go                       |  16 +-
 pkg/cli/deps_security.go                     |   4 +-
 pkg/cli/devcontainer.go                      |   5 +-
 pkg/cli/domains_command.go                   |   2 +-
 pkg/cli/enable.go                            |  24 +--
 pkg/cli/engine_secrets.go                    |  26 +--
 pkg/cli/fix_command.go                       |  14 +-
 pkg/cli/interactive.go                       |   2 +-
 pkg/cli/list_workflows_command.go            |   8 +-
 pkg/cli/logs_github_rate_limit_usage.go      |   3 +-
 pkg/cli/mcp_config_file.go                   |   5 +-
 pkg/cli/mcp_inspect_inspector.go             |  14 +-
 pkg/cli/mcp_inspect_list.go                  |   4 +-
 pkg/cli/mcp_inspect_mcp.go                   |  70 ++++----
 pkg/cli/mcp_list.go                          |   6 +-
 pkg/cli/mcp_list_tools.go                    |   4 +-
 pkg/cli/observability_insights.go            |   7 +-
 pkg/cli/preconditions.go                     |  28 +--
 pkg/cli/remove_command.go                    |  10 +-
 pkg/cli/run_interactive.go                   |   8 +-
 pkg/cli/run_push.go                          |   6 +-
 pkg/cli/secret_set_command.go                |   2 +-
 pkg/cli/shell_completion.go                  |  12 +-
 pkg/cli/token_usage.go                       |   5 +-
 pkg/cli/trial_confirmation.go                |   8 +-
 pkg/cli/update_actions.go                    |   2 +-
 pkg/cli/update_container_pins.go             |   4 +-
 pkg/cli/update_display.go                    |   2 +-
 pkg/cli/update_extension_check.go            |   4 +-
 pkg/cli/vscode_config.go                     |   3 +-
 pkg/workflow/action_sha_checker.go           |   4 +-
 pkg/workflow/cache.go                        |   5 +-
 pkg/workflow/claude_logs.go                  |   9 +-
 pkg/workflow/compiler_orchestrator_engine.go |   4 +-
 pkg/workflow/mcp_renderer.go                 |   3 +-
 pkg/workflow/push_to_pull_request_branch.go  |   3 +-
 pkg/workflow/side_repo_maintenance.go        |   5 +-
 process_file.py                              | 177 +++++++++++++++++++
 56 files changed, 512 insertions(+), 322 deletions(-)
 create mode 100755 process_file.py

diff --git a/pkg/cli/actionlint.go b/pkg/cli/actionlint.go
index 92f69cc584b..a518ca4a71e 100644
--- a/pkg/cli/actionlint.go
+++ b/pkg/cli/actionlint.go
@@ -94,9 +94,9 @@ func displayActionlintSummary() {
 	// Create visual separator
 	separator := strings.Repeat("━", 60)
 
-	fmt.Fprintf(os.Stderr, "\n%s\n", separator)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\n"+separator))
 	fmt.Fprintf(os.Stderr, "%s\n", console.FormatInfoMessage("Actionlint Summary"))
-	fmt.Fprintf(os.Stderr, "%s\n\n", separator)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(separator+"\n"))
 
 	// Show total workflows checked
 	fmt.Fprintf(os.Stderr, "%s\n",
@@ -119,7 +119,7 @@ func displayActionlintSummary() {
 		if len(actionlintStats.ErrorsByKind) > 0 {
 			fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("Issues by type:"))
 			for kind, count := range actionlintStats.ErrorsByKind {
-				fmt.Fprintf(os.Stderr, "  • %s: %d\n", kind, count)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  • %s: %d", kind, count)))
 			}
 		}
 	} else if actionlintStats.IntegrationErrors > 0 {
@@ -141,7 +141,7 @@ func displayActionlintSummary() {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatWarningMessage(msg))
 	}
 
-	fmt.Fprintf(os.Stderr, "\n%s\n", separator)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\n"+separator))
 }
 
 // getActionlintVersion fetches and caches the actionlint version from Docker
diff --git a/pkg/cli/add_interactive_engine.go b/pkg/cli/add_interactive_engine.go
index 5d7c17bc351..9dae8543b5a 100644
--- a/pkg/cli/add_interactive_engine.go
+++ b/pkg/cli/add_interactive_engine.go
@@ -74,7 +74,7 @@ func (c *AddInteractiveConfig) selectAIEngineAndKey() error {
 
 	// If engine is already overridden, skip selection
 	if c.EngineOverride != "" {
-		fmt.Fprintf(os.Stderr, "Using coding agent: %s\n", c.EngineOverride)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Using coding agent: "+c.EngineOverride))
 		return c.configureEngineAPISecret(c.EngineOverride)
 	}
 
diff --git a/pkg/cli/add_interactive_git.go b/pkg/cli/add_interactive_git.go
index 3ab419d1b81..b02f0967ec3 100644
--- a/pkg/cli/add_interactive_git.go
+++ b/pkg/cli/add_interactive_git.go
@@ -48,7 +48,7 @@ func (c *AddInteractiveConfig) createWorkflowPRAndConfigureSecret(ctx context.Co
 	// Step 8b: Optionally merge the PR – loop until merged, confirmed-merged, or user exits
 	if result.PRNumber == 0 {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Could not determine PR number"))
-		fmt.Fprintln(os.Stderr, "Please merge the PR manually from the GitHub web interface.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please merge the PR manually from the GitHub web interface."))
 	} else {
 		fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Pull request created: "+result.PRURL))
 		fmt.Fprintln(os.Stderr, "")
@@ -177,9 +177,9 @@ func (c *AddInteractiveConfig) createWorkflowPRAndConfigureSecret(ctx context.Co
 		if err := c.addRepositorySecret(secretName, secretValue); err != nil {
 			fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("Failed to add secret: %v", err)))
 			fmt.Fprintln(os.Stderr, "")
-			fmt.Fprintln(os.Stderr, "Please add the secret manually:")
-			fmt.Fprintln(os.Stderr, "  1. Go to your repository Settings → Secrets and variables → Actions")
-			fmt.Fprintf(os.Stderr, "  2. Click 'New repository secret' and add '%s'\n", secretName)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please add the secret manually:"))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  1. Go to your repository Settings → Secrets and variables → Actions"))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  2. Click 'New repository secret' and add '%s'", secretName)))
 			return fmt.Errorf("failed to add secret: %w", err)
 		}
 
@@ -266,8 +266,8 @@ func (c *AddInteractiveConfig) checkCleanWorkingDirectory() error {
 	if err := checkCleanWorkingDirectory(c.Verbose); err != nil {
 		fmt.Fprintln(os.Stderr, console.FormatErrorMessage("Working directory is not clean."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "The add wizard creates a pull request which requires a clean working directory.")
-		fmt.Fprintln(os.Stderr, "Please commit or stash your changes first:")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("The add wizard creates a pull request which requires a clean working directory."))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please commit or stash your changes first:"))
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatCommandMessage("  git stash        # Temporarily stash changes"))
 		fmt.Fprintln(os.Stderr, console.FormatCommandMessage("  git add -A && git commit -m 'wip'  # Commit changes"))
diff --git a/pkg/cli/add_interactive_orchestrator.go b/pkg/cli/add_interactive_orchestrator.go
index 48c22b49d61..d321e7a8b60 100644
--- a/pkg/cli/add_interactive_orchestrator.go
+++ b/pkg/cli/add_interactive_orchestrator.go
@@ -206,9 +206,9 @@ func (c *AddInteractiveConfig) determineFilesToAdd() (workflowFiles []string, in
 	}
 
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "The following workflow files will be added:")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("The following workflow files will be added:"))
 	for _, f := range workflowFiles {
-		fmt.Fprintf(os.Stderr, "  • .github/workflows/%s\n", f)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  • .github/workflows/"+f))
 	}
 
 	return workflowFiles, initFiles, nil
@@ -238,7 +238,7 @@ func (c *AddInteractiveConfig) confirmChanges(workflowFiles, initFiles []string,
 	}
 
 	if !confirmed {
-		fmt.Fprintln(os.Stderr, "Operation cancelled.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Operation cancelled."))
 		return errors.New("user cancelled the operation")
 	}
 
@@ -248,23 +248,23 @@ func (c *AddInteractiveConfig) confirmChanges(workflowFiles, initFiles []string,
 // showFinalInstructions shows final instructions to the user
 func (c *AddInteractiveConfig) showFinalInstructions() {
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))
 	fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("🎉 Addition complete!"))
-	fmt.Fprintln(os.Stderr, "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"))
 	fmt.Fprintln(os.Stderr, "")
 
 	// Show summary with workflow name(s)
 	if c.resolvedWorkflows != nil && len(c.resolvedWorkflows.Workflows) > 0 {
 		wf := c.resolvedWorkflows.Workflows[0]
-		fmt.Fprintf(os.Stderr, "The workflow '%s' has been added to the repository and will now run automatically.\n", wf.Spec.WorkflowName)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("The workflow '%s' has been added to the repository and will now run automatically.", wf.Spec.WorkflowName)))
 		c.showWorkflowDescriptions()
 	}
 
-	fmt.Fprintln(os.Stderr, "Useful commands:")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Useful commands:"))
 	fmt.Fprintln(os.Stderr, console.FormatCommandMessage(fmt.Sprintf("  %s status          # Check workflow status", string(constants.CLIExtensionPrefix))))
 	fmt.Fprintln(os.Stderr, console.FormatCommandMessage(fmt.Sprintf("  %s run <workflow>  # Trigger a workflow", string(constants.CLIExtensionPrefix))))
 	fmt.Fprintln(os.Stderr, console.FormatCommandMessage(fmt.Sprintf("  %s logs            # View workflow logs", string(constants.CLIExtensionPrefix))))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "Learn more at: https://github.github.com/gh-aw/")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Learn more at: https://github.github.com/gh-aw/"))
 	fmt.Fprintln(os.Stderr, "")
 }
diff --git a/pkg/cli/add_interactive_secrets.go b/pkg/cli/add_interactive_secrets.go
index 39663846743..a581cc3410d 100644
--- a/pkg/cli/add_interactive_secrets.go
+++ b/pkg/cli/add_interactive_secrets.go
@@ -5,6 +5,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/sliceutil"
 	"github.com/github/gh-aw/pkg/workflow"
 )
@@ -41,7 +42,7 @@ func (c *AddInteractiveConfig) checkExistingSecrets() error {
 	}
 
 	if c.Verbose && len(c.existingSecrets) > 0 {
-		fmt.Fprintf(os.Stderr, "Found %d existing secret(s) (repository + organization)\n", len(c.existingSecrets))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d existing secret(s) (repository + organization)", len(c.existingSecrets))))
 	}
 
 	return nil
diff --git a/pkg/cli/add_interactive_workflow.go b/pkg/cli/add_interactive_workflow.go
index ab9b1c7e042..009123ebec1 100644
--- a/pkg/cli/add_interactive_workflow.go
+++ b/pkg/cli/add_interactive_workflow.go
@@ -47,22 +47,22 @@ func (c *AddInteractiveConfig) checkStatusAndOfferRun(ctx context.Context) error
 			parsed, _ := parseWorkflowSpec(c.WorkflowSpecs[0])
 			if parsed != nil {
 				if c.Verbose {
-					fmt.Fprintf(os.Stderr, "Checking workflow status (attempt %d/5) for: %s\n", i+1, parsed.WorkflowName)
+					fmt.Fprintln(os.Stderr, console.FormatProgressMessage(fmt.Sprintf("Checking workflow status (attempt %d/5) for: %s", i+1, parsed.WorkflowName)))
 				}
 				// Check if workflow is in status
 				statuses, err := findWorkflowsByFilenamePattern(parsed.WorkflowName, c.RepoOverride, c.Verbose)
 				if err != nil {
 					if c.Verbose {
-						fmt.Fprintf(os.Stderr, "Status check error: %v\n", err)
+						fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("Status check error: %v", err)))
 					}
 				} else if len(statuses) > 0 {
 					if c.Verbose {
-						fmt.Fprintf(os.Stderr, "Found %d workflow(s) matching pattern\n", len(statuses))
+						fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d workflow(s) matching pattern", len(statuses))))
 					}
 					workflowFound = true
 					break
 				} else if c.Verbose {
-					fmt.Fprintln(os.Stderr, "No workflows found matching pattern yet")
+					fmt.Fprintln(os.Stderr, console.FormatInfoMessage("No workflows found matching pattern yet"))
 				}
 			}
 		}
@@ -74,7 +74,7 @@ func (c *AddInteractiveConfig) checkStatusAndOfferRun(ctx context.Context) error
 
 	if !workflowFound {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage("Could not verify workflow status."))
-		fmt.Fprintf(os.Stderr, "You can check status with: %s status\n", string(constants.CLIExtensionPrefix))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("You can check status with: %s status", string(constants.CLIExtensionPrefix))))
 		c.showFinalInstructions()
 		return nil
 	}
@@ -93,7 +93,7 @@ func (c *AddInteractiveConfig) checkStatusAndOfferRun(ctx context.Context) error
 		addInteractiveLog.Print("Running in Codespaces, skipping run offer and showing Actions link")
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Running in GitHub Codespaces - please trigger the workflow manually from the Actions page"))
-		fmt.Fprintf(os.Stderr, "🔗 https://github.com/%s/actions\n", c.RepoOverride)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("🔗 https://github.com/%s/actions", c.RepoOverride)))
 		c.showFinalInstructions()
 		return nil
 	}
@@ -132,15 +132,15 @@ func (c *AddInteractiveConfig) checkStatusAndOfferRun(ctx context.Context) error
 			// after the PR merge—avoids a race where git fetch runs before GitHub's git
 			// objects have been updated, which caused "workflow file not found" errors.
 			if !c.Verbose {
-				fmt.Fprintln(os.Stderr, "Updating local branch (this may take a few seconds)...")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Updating local branch (this may take a few seconds)..."))
 			}
 			if err := c.updateLocalBranch(); err != nil {
 				addInteractiveLog.Printf("Failed to update local branch: %v", err)
 				fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Could not update local branch: %v", err)))
-				fmt.Fprintln(os.Stderr, "You may need to switch to your repository's default branch (for example 'main') and run 'git pull' manually before running the workflow.")
+				fmt.Fprintln(os.Stderr, console.FormatProgressMessage("You may need to switch to your repository's default branch (for example 'main') and run 'git pull' manually before running the workflow."))
 			}
 			if !c.Verbose {
-				fmt.Fprintln(os.Stderr, "Finished updating local branch.")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Finished updating local branch."))
 			}
 
 			if err := RunSpecificWorkflowInteractively(ctx, parsed.WorkflowName, c.Verbose, c.EngineOverride, c.RepoOverride, "", false, false, false); err != nil {
@@ -155,7 +155,7 @@ func (c *AddInteractiveConfig) checkStatusAndOfferRun(ctx context.Context) error
 				fmt.Fprintln(os.Stderr, "")
 				fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Workflow triggered successfully!"))
 				fmt.Fprintln(os.Stderr, "")
-				fmt.Fprintf(os.Stderr, "🔗 View workflow run: %s\n", runInfo.URL)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🔗 View workflow run: "+runInfo.URL))
 			}
 		}
 	}
@@ -176,20 +176,20 @@ func findWorkflowsByFilenamePattern(pattern, repoOverride string, verbose bool)
 	}
 
 	if verbose {
-		fmt.Fprintf(os.Stderr, "Running: gh %s\n", strings.Join(args, " "))
+		fmt.Fprintln(os.Stderr, console.FormatProgressMessage("Running: gh "+strings.Join(args, " ")))
 	}
 
 	output, err := workflow.RunGH("Checking workflow status...", args...)
 	if err != nil {
 		if verbose {
-			fmt.Fprintf(os.Stderr, "gh workflow list failed: %v\n", err)
+			fmt.Fprintln(os.Stderr, console.FormatErrorMessage("gh workflow list failed: "+err.Error()))
 		}
 		return nil, err
 	}
 
 	if verbose {
-		fmt.Fprintf(os.Stderr, "gh workflow list output: %s\n", string(output))
-		fmt.Fprintf(os.Stderr, "Looking for workflow with filename containing: %s\n", pattern)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("gh workflow list output: "+string(output)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Looking for workflow with filename containing: "+pattern))
 	}
 
 	// Check if any workflow path contains the pattern
@@ -198,13 +198,13 @@ func findWorkflowsByFilenamePattern(pattern, repoOverride string, verbose bool)
 	// We check if the path contains the pattern
 	if strings.Contains(string(output), pattern+".lock.yml") || strings.Contains(string(output), pattern+".md") {
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Workflow with filename '%s' found in workflow list\n", pattern)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Workflow with filename '%s' found in workflow list", pattern)))
 		}
 		return []WorkflowStatus{{Workflow: pattern}}, nil
 	}
 
 	if verbose {
-		fmt.Fprintf(os.Stderr, "Workflow with filename '%s' NOT found in workflow list\n", pattern)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Workflow with filename '%s' NOT found in workflow list", pattern)))
 	}
 	return nil, nil
 }
diff --git a/pkg/cli/audit.go b/pkg/cli/audit.go
index 662fe03b336..518d5449cf2 100644
--- a/pkg/cli/audit.go
+++ b/pkg/cli/audit.go
@@ -745,18 +745,18 @@ func auditJobRun(runID int64, jobID int64, stepNumber int, owner, repo, hostname
 
 		// Display file locations
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\nDownloaded files:"))
-		fmt.Fprintf(os.Stderr, "  - %s (full job log)\n", jobLogPath)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  - %s (full job log)", jobLogPath)))
 
 		if stepNumber > 0 {
 			stepLogPath := filepath.Join(outputDir, fmt.Sprintf("job-%d-step-%d.log", jobID, stepNumber))
 			if _, err := os.Stat(stepLogPath); err == nil {
-				fmt.Fprintf(os.Stderr, "  - %s (step %d output)\n", stepLogPath, stepNumber)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  - %s (step %d output)", stepLogPath, stepNumber)))
 			}
 		} else {
 			failingStepPath := filepath.Join(outputDir, fmt.Sprintf("job-%d-step-*-failed.log", jobID))
 			matches, _ := filepath.Glob(failingStepPath)
 			for _, match := range matches {
-				fmt.Fprintf(os.Stderr, "  - %s (first failing step)\n", match)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  - %s (first failing step)", match)))
 			}
 		}
 	}
diff --git a/pkg/cli/audit_cross_run_render.go b/pkg/cli/audit_cross_run_render.go
index 8c6d7282df0..36a2257f960 100644
--- a/pkg/cli/audit_cross_run_render.go
+++ b/pkg/cli/audit_cross_run_render.go
@@ -213,13 +213,13 @@ func renderCrossRunReportPretty(report *CrossRunAuditReport) {
 
 	// Executive summary
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Executive Summary"))
-	fmt.Fprintf(os.Stderr, "  Runs analyzed:              %d\n", report.RunsAnalyzed)
-	fmt.Fprintf(os.Stderr, "  Runs with firewall data:    %d\n", report.RunsWithData)
-	fmt.Fprintf(os.Stderr, "  Runs without firewall data: %d\n", report.RunsWithoutData)
-	fmt.Fprintf(os.Stderr, "  Total requests:             %d\n", report.Summary.TotalRequests)
-	fmt.Fprintf(os.Stderr, "  Allowed / Blocked:          %d / %d\n", report.Summary.TotalAllowed, report.Summary.TotalBlocked)
-	fmt.Fprintf(os.Stderr, "  Overall denial rate:        %.1f%%\n", report.Summary.OverallDenyRate*100)
-	fmt.Fprintf(os.Stderr, "  Unique domains:             %d\n", report.Summary.UniqueDomains)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Runs analyzed:              %d", report.RunsAnalyzed)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Runs with firewall data:    %d", report.RunsWithData)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Runs without firewall data: %d", report.RunsWithoutData)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total requests:             %d", report.Summary.TotalRequests)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Allowed / Blocked:          %d / %d", report.Summary.TotalAllowed, report.Summary.TotalBlocked)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Overall denial rate:        %.1f%%", report.Summary.OverallDenyRate*100)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Unique domains:             %d", report.Summary.UniqueDomains)))
 	fmt.Fprintln(os.Stderr)
 
 	// Metrics trends
@@ -278,9 +278,9 @@ func renderCrossRunReportPretty(report *CrossRunAuditReport) {
 		fmt.Fprintf(os.Stderr, "  Runs with errors:  %d/%d (%.0f%%)\n",
 			et.RunsWithErrors, report.RunsAnalyzed,
 			safePercent(et.RunsWithErrors, report.RunsAnalyzed))
-		fmt.Fprintf(os.Stderr, "  Total errors:      %d (avg=%.2f/run)\n", et.TotalErrors, et.AvgErrorsPerRun)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total errors:      %d (avg=%.2f/run)", et.TotalErrors, et.AvgErrorsPerRun)))
 		if et.TotalWarnings > 0 {
-			fmt.Fprintf(os.Stderr, "  Total warnings:    %d (%d runs)\n", et.TotalWarnings, et.RunsWithWarnings)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total warnings:    %d (%d runs)", et.TotalWarnings, et.RunsWithWarnings)))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -310,10 +310,10 @@ func renderCrossRunReportPretty(report *CrossRunAuditReport) {
 			case "low":
 				severityIcon = "🟡"
 			}
-			fmt.Fprintf(os.Stderr, "  %s [%s/%s] %s\n", severityIcon, insight.Category, insight.Severity, insight.Title)
-			fmt.Fprintf(os.Stderr, "     %s\n", insight.Summary)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s [%s/%s] %s", severityIcon, insight.Category, insight.Severity, insight.Title)))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     "+insight.Summary))
 			if insight.Evidence != "" {
-				fmt.Fprintf(os.Stderr, "     evidence: %s\n", insight.Evidence)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     evidence: "+insight.Evidence))
 			}
 		}
 		fmt.Fprintln(os.Stderr)
diff --git a/pkg/cli/audit_report_render.go b/pkg/cli/audit_report_render.go
index 610adeec85b..f946804cd4a 100644
--- a/pkg/cli/audit_report_render.go
+++ b/pkg/cli/audit_report_render.go
@@ -164,10 +164,10 @@ func renderConsole(data AuditData, logsPath string) {
 		fmt.Fprintln(os.Stderr, console.FormatSectionHeader("Missing Tools"))
 		fmt.Fprintln(os.Stderr)
 		for _, tool := range data.MissingTools {
-			fmt.Fprintf(os.Stderr, "  • %s\n", tool.Tool)
-			fmt.Fprintf(os.Stderr, "    Reason: %s\n", tool.Reason)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  • "+tool.Tool))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    Reason: "+tool.Reason))
 			if tool.Alternatives != "" {
-				fmt.Fprintf(os.Stderr, "    Alternatives: %s\n", tool.Alternatives)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    Alternatives: "+tool.Alternatives))
 			}
 		}
 		fmt.Fprintln(os.Stderr)
@@ -185,7 +185,7 @@ func renderConsole(data AuditData, logsPath string) {
 		fmt.Fprintln(os.Stderr, console.FormatSectionHeader("MCP Server Failures"))
 		fmt.Fprintln(os.Stderr)
 		for _, failure := range data.MCPFailures {
-			fmt.Fprintf(os.Stderr, "  • %s: %s\n", failure.ServerName, failure.Status)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  • %s: %s", failure.ServerName, failure.Status)))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -236,7 +236,7 @@ func renderConsole(data AuditData, logsPath string) {
 	fmt.Fprintln(os.Stderr, console.FormatSectionHeader("Logs Location"))
 	fmt.Fprintln(os.Stderr)
 	absPath, _ := filepath.Abs(logsPath)
-	fmt.Fprintf(os.Stderr, "  %s\n", absPath)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  "+absPath))
 	fmt.Fprintln(os.Stderr)
 }
 
@@ -257,31 +257,31 @@ func renderAuditComparison(comparison *AuditComparisonData) {
 	}
 	fmt.Fprintln(os.Stderr)
 	if comparison.Baseline.Selection != "" {
-		fmt.Fprintf(os.Stderr, "  Selection: %s\n", strings.ReplaceAll(comparison.Baseline.Selection, "_", " "))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  Selection: "+strings.ReplaceAll(comparison.Baseline.Selection, "_", " ")))
 	}
 	if len(comparison.Baseline.MatchedOn) > 0 {
-		fmt.Fprintf(os.Stderr, "  Matched on: %s\n", strings.Join(comparison.Baseline.MatchedOn, ", "))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  Matched on: "+strings.Join(comparison.Baseline.MatchedOn, ", ")))
 	}
-	fmt.Fprintf(os.Stderr, "  Classification: %s\n", comparison.Classification.Label)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  Classification: "+comparison.Classification.Label))
 	fmt.Fprintln(os.Stderr, "  Changes:")
 
 	if comparison.Delta.Turns.Changed {
-		fmt.Fprintf(os.Stderr, "    - Turns: %d -> %d\n", comparison.Delta.Turns.Before, comparison.Delta.Turns.After)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    - Turns: %d -> %d", comparison.Delta.Turns.Before, comparison.Delta.Turns.After)))
 	}
 	if comparison.Delta.Posture.Changed {
-		fmt.Fprintf(os.Stderr, "    - Posture: %s -> %s\n", comparison.Delta.Posture.Before, comparison.Delta.Posture.After)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    - Posture: %s -> %s", comparison.Delta.Posture.Before, comparison.Delta.Posture.After)))
 	}
 	if comparison.Delta.BlockedRequests.Changed {
-		fmt.Fprintf(os.Stderr, "    - Blocked requests: %d -> %d\n", comparison.Delta.BlockedRequests.Before, comparison.Delta.BlockedRequests.After)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    - Blocked requests: %d -> %d", comparison.Delta.BlockedRequests.Before, comparison.Delta.BlockedRequests.After)))
 	}
 	if comparison.Delta.MCPFailure != nil && comparison.Delta.MCPFailure.NewlyPresent {
-		fmt.Fprintf(os.Stderr, "    - New MCP failure: %s\n", strings.Join(comparison.Delta.MCPFailure.After, ", "))
+		fmt.Fprintln(os.Stderr, console.FormatErrorMessage("    - New MCP failure: "+strings.Join(comparison.Delta.MCPFailure.After, ", ")))
 	}
 	if len(comparison.Classification.ReasonCodes) == 0 {
 		fmt.Fprintln(os.Stderr, "    - No meaningful behavior change from the selected successful baseline")
 	}
 	if comparison.Recommendation != nil && comparison.Recommendation.Action != "" {
-		fmt.Fprintf(os.Stderr, "  Recommended action: %s\n", comparison.Recommendation.Action)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  Recommended action: "+comparison.Recommendation.Action))
 	}
 	fmt.Fprintln(os.Stderr)
 }
diff --git a/pkg/cli/audit_report_render_findings.go b/pkg/cli/audit_report_render_findings.go
index d4052fba7f1..2ffcbe9d4ba 100644
--- a/pkg/cli/audit_report_render_findings.go
+++ b/pkg/cli/audit_report_render_findings.go
@@ -55,9 +55,9 @@ func renderKeyFindings(findings []Finding) {
 	// Render critical findings first
 	for _, finding := range critical {
 		fmt.Fprintf(os.Stderr, "  🔴 %s [%s]\n", console.FormatErrorMessage(finding.Title), finding.Category)
-		fmt.Fprintf(os.Stderr, "     %s\n", finding.Description)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     "+finding.Description))
 		if finding.Impact != "" {
-			fmt.Fprintf(os.Stderr, "     Impact: %s\n", finding.Impact)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Impact: "+finding.Impact))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -65,29 +65,29 @@ func renderKeyFindings(findings []Finding) {
 	// Then high severity
 	for _, finding := range high {
 		fmt.Fprintf(os.Stderr, "  🟠 %s [%s]\n", console.FormatWarningMessage(finding.Title), finding.Category)
-		fmt.Fprintf(os.Stderr, "     %s\n", finding.Description)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     "+finding.Description))
 		if finding.Impact != "" {
-			fmt.Fprintf(os.Stderr, "     Impact: %s\n", finding.Impact)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Impact: "+finding.Impact))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
 
 	// Medium severity
 	for _, finding := range medium {
-		fmt.Fprintf(os.Stderr, "  🟡 %s [%s]\n", finding.Title, finding.Category)
-		fmt.Fprintf(os.Stderr, "     %s\n", finding.Description)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  🟡 %s [%s]", finding.Title, finding.Category)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     "+finding.Description))
 		if finding.Impact != "" {
-			fmt.Fprintf(os.Stderr, "     Impact: %s\n", finding.Impact)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Impact: "+finding.Impact))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
 
 	// Low severity
 	for _, finding := range low {
-		fmt.Fprintf(os.Stderr, "  ℹ️  %s [%s]\n", finding.Title, finding.Category)
-		fmt.Fprintf(os.Stderr, "     %s\n", finding.Description)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  ℹ️  %s [%s]", finding.Title, finding.Category)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     "+finding.Description))
 		if finding.Impact != "" {
-			fmt.Fprintf(os.Stderr, "     Impact: %s\n", finding.Impact)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Impact: "+finding.Impact))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -95,9 +95,9 @@ func renderKeyFindings(findings []Finding) {
 	// Info findings
 	for _, finding := range info {
 		fmt.Fprintf(os.Stderr, "  ✅ %s [%s]\n", console.FormatSuccessMessage(finding.Title), finding.Category)
-		fmt.Fprintf(os.Stderr, "     %s\n", finding.Description)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     "+finding.Description))
 		if finding.Impact != "" {
-			fmt.Fprintf(os.Stderr, "     Impact: %s\n", finding.Impact)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Impact: "+finding.Impact))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -114,9 +114,9 @@ func renderRecommendations(recommendations []Recommendation) {
 	// Render high priority first
 	for i, rec := range high {
 		fmt.Fprintf(os.Stderr, "  %d. [HIGH] %s\n", i+1, console.FormatWarningMessage(rec.Action))
-		fmt.Fprintf(os.Stderr, "     Reason: %s\n", rec.Reason)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Reason: "+rec.Reason))
 		if rec.Example != "" {
-			fmt.Fprintf(os.Stderr, "     Example: %s\n", rec.Example)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Example: "+rec.Example))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -124,10 +124,10 @@ func renderRecommendations(recommendations []Recommendation) {
 	// Medium priority
 	startIdx := len(high) + 1
 	for i, rec := range medium {
-		fmt.Fprintf(os.Stderr, "  %d. [MEDIUM] %s\n", startIdx+i, rec.Action)
-		fmt.Fprintf(os.Stderr, "     Reason: %s\n", rec.Reason)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %d. [MEDIUM] %s", startIdx+i, rec.Action)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Reason: "+rec.Reason))
 		if rec.Example != "" {
-			fmt.Fprintf(os.Stderr, "     Example: %s\n", rec.Example)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Example: "+rec.Example))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -135,10 +135,10 @@ func renderRecommendations(recommendations []Recommendation) {
 	// Low priority
 	startIdx += len(medium)
 	for i, rec := range low {
-		fmt.Fprintf(os.Stderr, "  %d. [LOW] %s\n", startIdx+i, rec.Action)
-		fmt.Fprintf(os.Stderr, "     Reason: %s\n", rec.Reason)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %d. [LOW] %s", startIdx+i, rec.Action)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Reason: "+rec.Reason))
 		if rec.Example != "" {
-			fmt.Fprintf(os.Stderr, "     Example: %s\n", rec.Example)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     Example: "+rec.Example))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -149,8 +149,8 @@ func renderSafeOutputSummary(summary *SafeOutputSummary) {
 	if summary == nil {
 		return
 	}
-	fmt.Fprintf(os.Stderr, "  Total Items:       %d\n", summary.TotalItems)
-	fmt.Fprintf(os.Stderr, "  Summary:           %s\n", summary.Summary)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total Items:       %d", summary.TotalItems)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  Summary:           "+summary.Summary))
 	fmt.Fprintln(os.Stderr)
 
 	// Type breakdown table
@@ -181,7 +181,7 @@ func renderTokenUsage(summary *TokenUsageSummary) {
 	fmt.Fprintf(os.Stderr, "  Requests:   %d (avg %s)\n",
 		summary.TotalRequests, timeutil.FormatDurationMs(summary.AvgDurationMs()))
 	if summary.CacheEfficiency > 0 {
-		fmt.Fprintf(os.Stderr, "  Cache hit:  %.1f%%\n", summary.CacheEfficiency*100)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Cache hit:  %.1f%%", summary.CacheEfficiency*100)))
 	}
 	fmt.Fprintln(os.Stderr)
 
@@ -223,7 +223,7 @@ func renderGitHubRateLimitUsage(usage *GitHubRateLimitUsage) {
 			console.FormatNumber(usage.CoreRemaining),
 		)
 	}
-	fmt.Fprintf(os.Stderr, "  %s\n\n", summary)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s\n", summary)))
 
 	// Per-resource breakdown table (only when there are multiple resources or non-core resources)
 	rows := usage.ResourceRows()
@@ -253,9 +253,9 @@ func renderErrorsAndWarnings(errors []ErrorInfo, warnings []ErrorInfo) {
 		fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("Errors (%d):", len(errors))))
 		for _, err := range errors {
 			if err.File != "" && err.Line > 0 {
-				fmt.Fprintf(os.Stderr, "    %s:%d: %s\n", filepath.Base(err.File), err.Line, err.Message)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    %s:%d: %s", filepath.Base(err.File), err.Line, err.Message)))
 			} else {
-				fmt.Fprintf(os.Stderr, "    %s\n", err.Message)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    "+err.Message))
 			}
 		}
 		fmt.Fprintln(os.Stderr)
@@ -265,9 +265,9 @@ func renderErrorsAndWarnings(errors []ErrorInfo, warnings []ErrorInfo) {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warnings (%d):", len(warnings))))
 		for _, warn := range warnings {
 			if warn.File != "" && warn.Line > 0 {
-				fmt.Fprintf(os.Stderr, "    %s:%d: %s\n", filepath.Base(warn.File), warn.Line, warn.Message)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    %s:%d: %s", filepath.Base(warn.File), warn.Line, warn.Message)))
 			} else {
-				fmt.Fprintf(os.Stderr, "    %s\n", warn.Message)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    "+warn.Message))
 			}
 		}
 		fmt.Fprintln(os.Stderr)
diff --git a/pkg/cli/audit_report_render_firewall.go b/pkg/cli/audit_report_render_firewall.go
index 7317987bb1f..a0f1408f6ce 100644
--- a/pkg/cli/audit_report_render_firewall.go
+++ b/pkg/cli/audit_report_render_firewall.go
@@ -16,9 +16,9 @@ func renderFirewallAnalysis(analysis *FirewallAnalysis) {
 	auditReportLog.Printf("Rendering firewall analysis: total=%d, allowed=%d, blocked=%d, allowed_domains=%d, blocked_domains=%d",
 		analysis.TotalRequests, analysis.AllowedRequests, analysis.BlockedRequests, len(analysis.AllowedDomains), len(analysis.BlockedDomains))
 	// Summary statistics
-	fmt.Fprintf(os.Stderr, "  Total Requests : %d\n", analysis.TotalRequests)
-	fmt.Fprintf(os.Stderr, "  Allowed        : %d\n", analysis.AllowedRequests)
-	fmt.Fprintf(os.Stderr, "  Blocked        : %d\n", analysis.BlockedRequests)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total Requests : %d", analysis.TotalRequests)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Allowed        : %d", analysis.AllowedRequests)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Blocked        : %d", analysis.BlockedRequests)))
 	fmt.Fprintln(os.Stderr)
 
 	// Allowed domains
@@ -26,7 +26,7 @@ func renderFirewallAnalysis(analysis *FirewallAnalysis) {
 		fmt.Fprintln(os.Stderr, "  Allowed Domains:")
 		for _, domain := range analysis.AllowedDomains {
 			if stats, ok := analysis.RequestsByDomain[domain]; ok {
-				fmt.Fprintf(os.Stderr, "    ✓ %s (%d requests)\n", domain, stats.Allowed)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    ✓ %s (%d requests)", domain, stats.Allowed)))
 			}
 		}
 		fmt.Fprintln(os.Stderr)
@@ -37,7 +37,7 @@ func renderFirewallAnalysis(analysis *FirewallAnalysis) {
 		fmt.Fprintln(os.Stderr, "  Blocked Domains:")
 		for _, domain := range analysis.BlockedDomains {
 			if stats, ok := analysis.RequestsByDomain[domain]; ok {
-				fmt.Fprintf(os.Stderr, "    ✗ %s (%d requests)\n", domain, stats.Blocked)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    ✗ %s (%d requests)", domain, stats.Blocked)))
 			}
 		}
 		fmt.Fprintln(os.Stderr)
@@ -48,14 +48,14 @@ func renderFirewallAnalysis(analysis *FirewallAnalysis) {
 func renderRedactedDomainsAnalysis(analysis *RedactedDomainsAnalysis) {
 	auditReportLog.Printf("Rendering redacted domains analysis: total_domains=%d", analysis.TotalDomains)
 	// Summary statistics
-	fmt.Fprintf(os.Stderr, "  Total Domains Redacted: %d\n", analysis.TotalDomains)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total Domains Redacted: %d", analysis.TotalDomains)))
 	fmt.Fprintln(os.Stderr)
 
 	// List domains
 	if len(analysis.Domains) > 0 {
 		fmt.Fprintln(os.Stderr, "  Redacted Domains:")
 		for _, domain := range analysis.Domains {
-			fmt.Fprintf(os.Stderr, "    🔒 %s\n", domain)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    🔒 %s", domain)))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
diff --git a/pkg/cli/audit_report_render_guard.go b/pkg/cli/audit_report_render_guard.go
index ad154776fda..20f573e8df4 100644
--- a/pkg/cli/audit_report_render_guard.go
+++ b/pkg/cli/audit_report_render_guard.go
@@ -23,22 +23,22 @@ func renderGuardPolicySummary(summary *GuardPolicySummary) {
 	// Breakdown by reason
 	fmt.Fprintln(os.Stderr, "  Block Reasons:")
 	if summary.IntegrityBlocked > 0 {
-		fmt.Fprintf(os.Stderr, "    Integrity below minimum : %d\n", summary.IntegrityBlocked)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Integrity below minimum : %d", summary.IntegrityBlocked)))
 	}
 	if summary.RepoScopeBlocked > 0 {
-		fmt.Fprintf(os.Stderr, "    Repository not allowed  : %d\n", summary.RepoScopeBlocked)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Repository not allowed  : %d", summary.RepoScopeBlocked)))
 	}
 	if summary.AccessDenied > 0 {
-		fmt.Fprintf(os.Stderr, "    Access denied           : %d\n", summary.AccessDenied)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Access denied           : %d", summary.AccessDenied)))
 	}
 	if summary.BlockedUserDenied > 0 {
-		fmt.Fprintf(os.Stderr, "    Blocked user            : %d\n", summary.BlockedUserDenied)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Blocked user            : %d", summary.BlockedUserDenied)))
 	}
 	if summary.PermissionDenied > 0 {
-		fmt.Fprintf(os.Stderr, "    Insufficient permissions: %d\n", summary.PermissionDenied)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Insufficient permissions: %d", summary.PermissionDenied)))
 	}
 	if summary.PrivateRepoDenied > 0 {
-		fmt.Fprintf(os.Stderr, "    Private repo denied     : %d\n", summary.PrivateRepoDenied)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Private repo denied     : %d", summary.PrivateRepoDenied)))
 	}
 	fmt.Fprintln(os.Stderr)
 
diff --git a/pkg/cli/audit_report_render_overview.go b/pkg/cli/audit_report_render_overview.go
index 07254aedb76..a9454a141ee 100644
--- a/pkg/cli/audit_report_render_overview.go
+++ b/pkg/cli/audit_report_render_overview.go
@@ -74,12 +74,12 @@ func renderBehaviorFingerprint(fingerprint *BehaviorFingerprint) {
 func renderAgenticAssessments(assessments []AgenticAssessment) {
 	for _, assessment := range assessments {
 		severity := strings.ToUpper(assessment.Severity)
-		fmt.Fprintf(os.Stderr, "  [%s] %s\n", severity, assessment.Summary)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  [%s] %s", severity, assessment.Summary)))
 		if assessment.Evidence != "" {
-			fmt.Fprintf(os.Stderr, "     Evidence: %s\n", assessment.Evidence)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("     Evidence: %s", assessment.Evidence)))
 		}
 		if assessment.Recommendation != "" {
-			fmt.Fprintf(os.Stderr, "     Recommendation: %s\n", assessment.Recommendation)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("     Recommendation: %s", assessment.Recommendation)))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
@@ -90,7 +90,7 @@ func renderPerformanceMetrics(metrics *PerformanceMetrics) {
 	auditReportLog.Printf("Rendering performance metrics: tokens_per_min=%.1f, cost_efficiency=%s, most_used_tool=%s",
 		metrics.TokensPerMinute, metrics.CostEfficiency, metrics.MostUsedTool)
 	if metrics.TokensPerMinute > 0 {
-		fmt.Fprintf(os.Stderr, "  Tokens per Minute: %.1f\n", metrics.TokensPerMinute)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Tokens per Minute: %.1f", metrics.TokensPerMinute)))
 	}
 
 	if metrics.CostEfficiency != "" {
@@ -103,19 +103,19 @@ func renderPerformanceMetrics(metrics *PerformanceMetrics) {
 		case "poor":
 			efficiencyDisplay = console.FormatErrorMessage(metrics.CostEfficiency)
 		}
-		fmt.Fprintf(os.Stderr, "  Cost Efficiency: %s\n", efficiencyDisplay)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Cost Efficiency: %s", efficiencyDisplay)))
 	}
 
 	if metrics.AvgToolDuration != "" {
-		fmt.Fprintf(os.Stderr, "  Average Tool Duration: %s\n", metrics.AvgToolDuration)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Average Tool Duration: %s", metrics.AvgToolDuration)))
 	}
 
 	if metrics.MostUsedTool != "" {
-		fmt.Fprintf(os.Stderr, "  Most Used Tool: %s\n", metrics.MostUsedTool)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Most Used Tool: %s", metrics.MostUsedTool)))
 	}
 
 	if metrics.NetworkRequests > 0 {
-		fmt.Fprintf(os.Stderr, "  Network Requests: %d\n", metrics.NetworkRequests)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Network Requests: %d", metrics.NetworkRequests)))
 	}
 
 	fmt.Fprintln(os.Stderr)
@@ -126,30 +126,30 @@ func renderEngineConfig(config *AuditEngineConfig) {
 	if config == nil {
 		return
 	}
-	fmt.Fprintf(os.Stderr, "  Engine ID:         %s\n", config.EngineID)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Engine ID:         %s", config.EngineID)))
 	if config.EngineName != "" {
-		fmt.Fprintf(os.Stderr, "  Engine Name:       %s\n", config.EngineName)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Engine Name:       %s", config.EngineName)))
 	}
 	if config.Model != "" {
-		fmt.Fprintf(os.Stderr, "  Model:             %s\n", config.Model)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Model:             %s", config.Model)))
 	}
 	if config.Version != "" {
-		fmt.Fprintf(os.Stderr, "  Version:           %s\n", config.Version)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Version:           %s", config.Version)))
 	}
 	if config.CLIVersion != "" {
-		fmt.Fprintf(os.Stderr, "  CLI Version:       %s\n", config.CLIVersion)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  CLI Version:       %s", config.CLIVersion)))
 	}
 	if config.FirewallVersion != "" {
-		fmt.Fprintf(os.Stderr, "  Firewall Version:  %s\n", config.FirewallVersion)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Firewall Version:  %s", config.FirewallVersion)))
 	}
 	if config.TriggerEvent != "" {
-		fmt.Fprintf(os.Stderr, "  Trigger Event:     %s\n", config.TriggerEvent)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Trigger Event:     %s", config.TriggerEvent)))
 	}
 	if config.Repository != "" {
-		fmt.Fprintf(os.Stderr, "  Repository:        %s\n", config.Repository)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Repository:        %s", config.Repository)))
 	}
 	if len(config.MCPServers) > 0 {
-		fmt.Fprintf(os.Stderr, "  MCP Servers:       %s\n", strings.Join(config.MCPServers, ", "))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  MCP Servers:       %s", strings.Join(config.MCPServers, ", "))))
 	}
 	fmt.Fprintln(os.Stderr)
 }
@@ -161,7 +161,7 @@ func renderPromptAnalysis(analysis *PromptAnalysis) {
 	}
 	fmt.Fprintf(os.Stderr, "  Prompt Size:       %s chars\n", console.FormatNumber(analysis.PromptSize))
 	if analysis.PromptFile != "" {
-		fmt.Fprintf(os.Stderr, "  Prompt File:       %s\n", analysis.PromptFile)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Prompt File:       %s", analysis.PromptFile)))
 	}
 	fmt.Fprintln(os.Stderr)
 }
@@ -172,28 +172,28 @@ func renderSessionAnalysis(session *SessionAnalysis) {
 		return
 	}
 	if session.WallTime != "" {
-		fmt.Fprintf(os.Stderr, "  Wall Time:              %s\n", session.WallTime)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Wall Time:              %s", session.WallTime)))
 	}
 	if session.TurnCount > 0 {
-		fmt.Fprintf(os.Stderr, "  Turn Count:             %d\n", session.TurnCount)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Turn Count:             %d", session.TurnCount)))
 	}
 	if session.AvgTurnDuration != "" {
-		fmt.Fprintf(os.Stderr, "  Avg Turn Duration:      %s\n", session.AvgTurnDuration)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Avg Turn Duration:      %s", session.AvgTurnDuration)))
 	}
 	if session.AvgTimeBetweenTurns != "" {
-		fmt.Fprintf(os.Stderr, "  Avg Time Between Turns: %s\n", session.AvgTimeBetweenTurns)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Avg Time Between Turns: %s", session.AvgTimeBetweenTurns)))
 	}
 	if session.MaxTimeBetweenTurns != "" {
-		fmt.Fprintf(os.Stderr, "  Max Time Between Turns: %s\n", session.MaxTimeBetweenTurns)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Max Time Between Turns: %s", session.MaxTimeBetweenTurns)))
 	}
 	if session.CacheWarning != "" {
 		fmt.Fprintf(os.Stderr, "  Cache Warning:          %s\n", console.FormatWarningMessage(session.CacheWarning))
 	}
 	if session.TokensPerMinute > 0 {
-		fmt.Fprintf(os.Stderr, "  Tokens/Minute:          %.1f\n", session.TokensPerMinute)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Tokens/Minute:          %.1f", session.TokensPerMinute)))
 	}
 	if session.NoopCount > 0 {
-		fmt.Fprintf(os.Stderr, "  Noop Count:             %d\n", session.NoopCount)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Noop Count:             %d", session.NoopCount)))
 	}
 	if session.TimeoutDetected {
 		fmt.Fprintf(os.Stderr, "  Timeout Detected:       %s\n", console.FormatWarningMessage("Yes"))
diff --git a/pkg/cli/audit_report_render_tools.go b/pkg/cli/audit_report_render_tools.go
index 8ea851bdfcd..cc1f681e552 100644
--- a/pkg/cli/audit_report_render_tools.go
+++ b/pkg/cli/audit_report_render_tools.go
@@ -128,11 +128,11 @@ func renderMCPServerHealth(health *MCPServerHealth) {
 	if health == nil {
 		return
 	}
-	fmt.Fprintf(os.Stderr, "  %s\n", health.Summary)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s", health.Summary)))
 	if health.TotalRequests > 0 {
-		fmt.Fprintf(os.Stderr, "  Total Requests:    %d\n", health.TotalRequests)
-		fmt.Fprintf(os.Stderr, "  Total Errors:      %d\n", health.TotalErrors)
-		fmt.Fprintf(os.Stderr, "  Error Rate:        %.1f%%\n", health.ErrorRate)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total Requests:    %d", health.TotalRequests)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total Errors:      %d", health.TotalErrors)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Error Rate:        %.1f%%", health.ErrorRate)))
 	}
 	fmt.Fprintln(os.Stderr)
 
diff --git a/pkg/cli/compile_file_operations.go b/pkg/cli/compile_file_operations.go
index b068a1cd627..73273016d8f 100644
--- a/pkg/cli/compile_file_operations.go
+++ b/pkg/cli/compile_file_operations.go
@@ -210,7 +210,7 @@ func compileModifiedFilesWithDependencies(compiler *workflow.Compiler, depGraph
 		}
 	}
 
-	fmt.Fprintln(os.Stderr, "Watching for file changes")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Watching for file changes"))
 	if verbose {
 		fmt.Fprintln(os.Stderr, console.FormatProgressMessage(fmt.Sprintf("Recompiling %d workflow(s) affected by %d change(s)...", len(workflowsToCompile), len(files))))
 	}
diff --git a/pkg/cli/compile_stats.go b/pkg/cli/compile_stats.go
index c5e0c48de55..332536d0858 100644
--- a/pkg/cli/compile_stats.go
+++ b/pkg/cli/compile_stats.go
@@ -139,7 +139,7 @@ func printCompilationSummary(stats *CompilationStats) {
 			fmt.Fprintln(os.Stderr)
 			fmt.Fprintln(os.Stderr, console.FormatErrorMessage("Failed workflows:"))
 			for _, failure := range stats.FailureDetails {
-				fmt.Fprintf(os.Stderr, "  ✗ %s\n", filepath.Base(failure.Path))
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  ✗ %s", filepath.Base(failure.Path))))
 			}
 			fmt.Fprintln(os.Stderr)
 
@@ -154,7 +154,7 @@ func printCompilationSummary(stats *CompilationStats) {
 			fmt.Fprintln(os.Stderr)
 			fmt.Fprintln(os.Stderr, console.FormatErrorMessage("Failed workflows:"))
 			for _, workflow := range stats.FailedWorkflows {
-				fmt.Fprintf(os.Stderr, "  ✗ %s\n", workflow)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  ✗ %s", workflow)))
 			}
 			fmt.Fprintln(os.Stderr)
 		}
@@ -264,11 +264,11 @@ func displayStatsTable(statsList []*WorkflowStats) {
 	// Print summary
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Summary:"))
 	if len(statsList) > maxDisplay {
-		fmt.Fprintf(os.Stderr, "  Showing top %d of %d workflows (sorted by size)\n", maxDisplay, len(statsList))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Showing top %d of %d workflows (sorted by size)", maxDisplay, len(statsList))))
 	}
-	fmt.Fprintf(os.Stderr, "  Total workflows: %d\n", len(statsList))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total workflows: %d", len(statsList))))
 	fmt.Fprintf(os.Stderr, "  Total size:      %s\n", console.FormatFileSize(totalSize))
-	fmt.Fprintf(os.Stderr, "  Total jobs:      %d\n", totalJobs)
-	fmt.Fprintf(os.Stderr, "  Total steps:     %d\n", totalSteps)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total jobs:      %d", totalJobs)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Total steps:     %d", totalSteps)))
 	fmt.Fprintf(os.Stderr, "  Total scripts:   %d (%s)\n", totalScripts, console.FormatFileSize(int64(totalScriptSize)))
 }
diff --git a/pkg/cli/copilot_agents.go b/pkg/cli/copilot_agents.go
index 5a6c278c7ce..af3c56a7520 100644
--- a/pkg/cli/copilot_agents.go
+++ b/pkg/cli/copilot_agents.go
@@ -117,7 +117,7 @@ func deleteSetupAgenticWorkflowsAgent(verbose bool) error {
 			return fmt.Errorf("failed to remove setup-agentic-workflows agent: %w", err)
 		}
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Removed setup-agentic-workflows agent: %s\n", agentPath)
+			fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Removed setup-agentic-workflows agent: %s", agentPath)))
 		}
 	}
 
@@ -215,7 +215,7 @@ func deleteOldAgentFiles(verbose bool) error {
 					return fmt.Errorf("failed to remove old %s file %s: %w", subdir, file, err)
 				}
 				if verbose {
-					fmt.Fprintf(os.Stderr, "Removed old %s file: %s\n", subdir, path)
+					fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Removed old %s file: %s", subdir, path)))
 				}
 			}
 		}
diff --git a/pkg/cli/copilot_setup.go b/pkg/cli/copilot_setup.go
index c7071672cad..df464127f43 100644
--- a/pkg/cli/copilot_setup.go
+++ b/pkg/cli/copilot_setup.go
@@ -8,6 +8,7 @@ import (
 	"regexp"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 	"github.com/github/gh-aw/pkg/workflow"
 )
@@ -219,7 +220,7 @@ func ensureCopilotSetupStepsWithUpgrade(verbose bool, actionMode workflow.Action
 			if !upgraded {
 				copilotSetupLog.Print("No version upgrade needed")
 				if verbose {
-					fmt.Fprintf(os.Stderr, "No version upgrade needed for %s\n", setupStepsPath)
+					fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("No version upgrade needed for %s", setupStepsPath)))
 				}
 				return nil
 			}
@@ -230,7 +231,7 @@ func ensureCopilotSetupStepsWithUpgrade(verbose bool, actionMode workflow.Action
 			copilotSetupLog.Printf("Upgraded version in file: %s", setupStepsPath)
 
 			if verbose {
-				fmt.Fprintf(os.Stderr, "Updated %s with new version %s\n", setupStepsPath, version)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Updated %s with new version %s", setupStepsPath, version)))
 			}
 			return nil
 		}
@@ -239,7 +240,7 @@ func ensureCopilotSetupStepsWithUpgrade(verbose bool, actionMode workflow.Action
 		if hasLegacyInstall || hasActionInstall {
 			copilotSetupLog.Print("Extension install step already exists, file is up to date")
 			if verbose {
-				fmt.Fprintf(os.Stderr, "Skipping %s (already has gh-aw extension install step)\n", setupStepsPath)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Skipping %s (already has gh-aw extension install step)", setupStepsPath)))
 			}
 			return nil
 		}
@@ -266,8 +267,8 @@ func renderCopilotSetupUpdateInstructions(filePath string, actionMode workflow.A
 		"ℹ",
 		"Existing file detected: "+filePath)
 	fmt.Fprintln(os.Stderr)
-	fmt.Fprintln(os.Stderr, "To enable GitHub Copilot Agent integration, please add the following steps")
-	fmt.Fprintln(os.Stderr, "to the 'copilot-setup-steps' job in your .github/workflows/copilot-setup-steps.yml file:")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To enable GitHub Copilot Agent integration, please add the following steps"))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("to the 'copilot-setup-steps' job in your .github/workflows/copilot-setup-steps.yml file:"))
 	fmt.Fprintln(os.Stderr)
 
 	// Determine the action reference
@@ -278,16 +279,16 @@ func renderCopilotSetupUpdateInstructions(filePath string, actionMode workflow.A
 		if actionMode.IsAction() {
 			actionRepo = "github/gh-aw-actions/setup-cli"
 		}
-		fmt.Fprintln(os.Stderr, "      - name: Checkout repository")
-		fmt.Fprintln(os.Stderr, "        uses: actions/checkout@v6")
-		fmt.Fprintf(os.Stderr, "      - name: Install gh-aw extension\n")
-		fmt.Fprintf(os.Stderr, "        uses: %s%s\n", actionRepo, actionRef)
-		fmt.Fprintln(os.Stderr, "        with:")
-		fmt.Fprintf(os.Stderr, "          version: %s\n", version)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("      - name: Checkout repository"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("        uses: actions/checkout@v6"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("      - name: Install gh-aw extension"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("        uses: %s%s", actionRepo, actionRef)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("        with:"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("          version: %s", version)))
 	} else {
-		fmt.Fprintln(os.Stderr, "      - name: Install gh-aw extension")
-		fmt.Fprintln(os.Stderr, "        run: |")
-		fmt.Fprintln(os.Stderr, "          curl -fsSL https://raw.githubusercontent.com/github/gh-aw/refs/heads/main/install-gh-aw.sh | bash")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("      - name: Install gh-aw extension"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("        run: |"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("          curl -fsSL https://raw.githubusercontent.com/github/gh-aw/refs/heads/main/install-gh-aw.sh | bash"))
 	}
 	fmt.Fprintln(os.Stderr)
 }
diff --git a/pkg/cli/deps_report.go b/pkg/cli/deps_report.go
index f3cacbe46a8..42e5f9a71c9 100644
--- a/pkg/cli/deps_report.go
+++ b/pkg/cli/deps_report.go
@@ -109,14 +109,14 @@ func DisplayDependencyReport(report *DependencyReport) {
 	// Summary section
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Summary"))
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("-------"))
-	fmt.Fprintf(os.Stderr, "Total dependencies: %d (%d direct, %d indirect)\n", report.TotalDeps, report.DirectDeps, report.IndirectDeps)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Total dependencies: %d (%d direct, %d indirect)", report.TotalDeps, report.DirectDeps, report.IndirectDeps)))
 
 	outdatedPercentage := 0.0
 	if report.DirectDeps > 0 {
 		outdatedPercentage = float64(len(report.Outdated)) / float64(report.DirectDeps) * 100
 	}
-	fmt.Fprintf(os.Stderr, "Outdated: %d (%.0f%%)\n", len(report.Outdated), outdatedPercentage)
-	fmt.Fprintf(os.Stderr, "Security advisories: %d\n", len(report.Advisories))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Outdated: %d (%.0f%%)", len(report.Outdated), outdatedPercentage)))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Security advisories: %d", len(report.Advisories))))
 
 	v0Percentage := 0.0
 	if report.TotalDeps > 0 {
@@ -160,13 +160,13 @@ func DisplayDependencyReport(report *DependencyReport) {
 	if report.TotalDeps > 0 {
 		v1Percentage = float64(report.V1PlusCount) / float64(report.TotalDeps) * 100
 	}
-	fmt.Fprintf(os.Stderr, "v1.x (stable): %d (%.0f%%)\n", report.V1PlusCount, v1Percentage)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("v1.x (stable): %d (%.0f%%)", report.V1PlusCount, v1Percentage)))
 
 	v2Percentage := 0.0
 	if report.TotalDeps > 0 {
 		v2Percentage = float64(report.V2PlusCount) / float64(report.TotalDeps) * 100
 	}
-	fmt.Fprintf(os.Stderr, "v2+ (mature): %d (%.0f%%)\n", report.V2PlusCount, v2Percentage)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("v2+ (mature): %d (%.0f%%)", report.V2PlusCount, v2Percentage)))
 	fmt.Fprintln(os.Stderr, "")
 
 	// Recommendations section
@@ -175,15 +175,15 @@ func DisplayDependencyReport(report *DependencyReport) {
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("---------------"))
 
 		if len(report.Advisories) > 0 {
-			fmt.Fprintf(os.Stderr, "🔴 CRITICAL: Address %d security %s immediately\n", len(report.Advisories), pluralize("advisory", len(report.Advisories)))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("🔴 CRITICAL: Address %d security %s immediately", len(report.Advisories), pluralize("advisory", len(report.Advisories)))))
 		}
 
 		if len(report.Outdated) > 0 {
-			fmt.Fprintf(os.Stderr, "📦 Update %d outdated %s\n", len(report.Outdated), pluralize("dependency", len(report.Outdated)))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("📦 Update %d outdated %s", len(report.Outdated), pluralize("dependency", len(report.Outdated)))))
 		}
 
 		if v0Percentage > 30 {
-			fmt.Fprintf(os.Stderr, "⚠️  Reduce v0.x exposure from %.0f%% to <30%%\n", v0Percentage)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("⚠️  Reduce v0.x exposure from %.0f%% to <30%%", v0Percentage)))
 		}
 
 		fmt.Fprintln(os.Stderr, "")
diff --git a/pkg/cli/deps_security.go b/pkg/cli/deps_security.go
index 71304dd2c17..a1996038d1c 100644
--- a/pkg/cli/deps_security.go
+++ b/pkg/cli/deps_security.go
@@ -121,10 +121,10 @@ func DisplaySecurityAdvisories(advisories []SecurityAdvisory) {
 		fmt.Fprintln(os.Stderr, "")
 
 		if len(adv.PatchedVers) > 0 {
-			fmt.Fprintf(os.Stderr, "    Fixed in: %s\n", strings.Join(adv.PatchedVers, ", "))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Fixed in: %s", strings.Join(adv.PatchedVers, ", "))))
 		}
 
-		fmt.Fprintf(os.Stderr, "    %s\n", adv.URL)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    %s", adv.URL)))
 		fmt.Fprintln(os.Stderr, "")
 	}
 }
diff --git a/pkg/cli/devcontainer.go b/pkg/cli/devcontainer.go
index bf2eedfb972..92aa2cac853 100644
--- a/pkg/cli/devcontainer.go
+++ b/pkg/cli/devcontainer.go
@@ -8,6 +8,7 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/gitutil"
 	"github.com/github/gh-aw/pkg/logger"
 )
@@ -162,7 +163,7 @@ func ensureDevcontainerConfig(verbose bool, additionalRepos []string) error {
 		}
 
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Updated existing devcontainer at %s\n", devcontainerPath)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Updated existing devcontainer at %s", devcontainerPath)))
 		}
 	} else {
 		// Create new configuration
@@ -189,7 +190,7 @@ func ensureDevcontainerConfig(verbose bool, additionalRepos []string) error {
 		}
 
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Created new devcontainer at %s\n", devcontainerPath)
+			fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Created new devcontainer at %s", devcontainerPath)))
 		}
 	}
 
diff --git a/pkg/cli/domains_command.go b/pkg/cli/domains_command.go
index 993fc845303..9af6997eccc 100644
--- a/pkg/cli/domains_command.go
+++ b/pkg/cli/domains_command.go
@@ -191,7 +191,7 @@ func RunWorkflowDomains(workflowArg string, jsonOutput bool) error {
 	}
 	fmt.Fprint(os.Stderr, console.RenderTable(tableConfig))
 
-	fmt.Fprintf(os.Stderr, "\n%d allowed, %d blocked\n", len(allowedDomains), len(blockedDomains))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\n%d allowed, %d blocked", len(allowedDomains), len(blockedDomains))))
 
 	return nil
 }
diff --git a/pkg/cli/enable.go b/pkg/cli/enable.go
index aed89e2ef57..63718fae708 100644
--- a/pkg/cli/enable.go
+++ b/pkg/cli/enable.go
@@ -43,7 +43,7 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st
 	// If no specific workflow names provided, enable/disable all workflows
 	if len(workflowNames) == 0 {
 		enableLog.Print("No specific workflows provided, processing all workflows")
-		fmt.Fprintf(os.Stderr, "No specific workflows provided. %sing all workflows...\n", strings.ToUpper(action[:1])+action[1:])
+		fmt.Fprintln(os.Stderr, console.FormatProgressMessage(fmt.Sprintf("%sing all workflows...", strings.ToUpper(action[:1])+action[1:])))
 		// Get all workflow names and process them
 		mdFiles, err := getMarkdownWorkflowFiles("")
 		if err != nil {
@@ -133,12 +133,12 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st
 				if exists {
 					if enable && githubWorkflow.State == "active" {
 						// Already enabled
-						fmt.Fprintf(os.Stderr, "Workflow %s is already enabled\n", name)
+						fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Workflow %s is already enabled", name)))
 						continue
 					}
 					if !enable && githubWorkflow.State == "disabled_manually" {
 						// Already disabled
-						fmt.Fprintf(os.Stderr, "Workflow %s is already disabled\n", name)
+						fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Workflow %s is already disabled", name)))
 						continue
 					}
 				}
@@ -189,15 +189,15 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st
 	// If no targets after filtering, everything was already in the desired state
 	if len(targets) == 0 {
 		enableLog.Printf("No workflows need to be %sd - all already in desired state", action)
-		fmt.Fprintf(os.Stderr, "All specified workflows are already %sd\n", action)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("All specified workflows are already %sd", action)))
 		return nil
 	}
 
 	enableLog.Printf("Proceeding to %s %d workflows", action, len(targets))
 	// Show what will be changed
-	fmt.Fprintf(os.Stderr, "The following workflows will be %sd:\n", action)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("The following workflows will be %sd:", action)))
 	for _, t := range targets {
-		fmt.Fprintf(os.Stderr, "  %s (current state: %s)\n", t.Name, t.CurrentState)
+		fmt.Fprintln(os.Stderr, console.FormatListItem(fmt.Sprintf("%s (current state: %s)", t.Name, t.CurrentState)))
 	}
 
 	// Perform the action
@@ -257,7 +257,7 @@ func toggleWorkflowsByNames(workflowNames []string, enable bool, repoOverride st
 			}
 			failures = append(failures, t.Name)
 		} else {
-			fmt.Fprintf(os.Stderr, "%sd workflow: %s\n", strings.ToUpper(action[:1])+action[1:], t.Name)
+			fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("%sd workflow: %s", strings.ToUpper(action[:1])+action[1:], t.Name)))
 		}
 	}
 
@@ -318,7 +318,7 @@ func DisableAllWorkflowsExcept(repoSlug string, exceptWorkflows []string, verbos
 		// Skip if it's in the keep-enabled set
 		if keepEnabled[base] {
 			if verbose {
-				fmt.Fprintf(os.Stderr, "Keeping enabled: %s\n", base)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Keeping enabled: %s", base)))
 			}
 			continue
 		}
@@ -327,7 +327,7 @@ func DisableAllWorkflowsExcept(repoSlug string, exceptWorkflows []string, verbos
 		nameWithoutExt := strings.TrimSuffix(base, filepath.Ext(base))
 		if keepEnabled[nameWithoutExt] {
 			if verbose {
-				fmt.Fprintf(os.Stderr, "Keeping enabled: %s\n", base)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Keeping enabled: %s", base)))
 			}
 			continue
 		}
@@ -343,9 +343,9 @@ func DisableAllWorkflowsExcept(repoSlug string, exceptWorkflows []string, verbos
 	}
 
 	// Show what will be disabled
-	fmt.Fprintf(os.Stderr, "Disabling %d workflow(s) in cloned repository:\n", len(workflowsToDisable))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Disabling %d workflow(s) in cloned repository:", len(workflowsToDisable))))
 	for _, wf := range workflowsToDisable {
-		fmt.Fprintf(os.Stderr, "  %s\n", wf)
+		fmt.Fprintln(os.Stderr, console.FormatListItem(wf))
 	}
 
 	// Disable each workflow
@@ -364,7 +364,7 @@ func DisableAllWorkflowsExcept(repoSlug string, exceptWorkflows []string, verbos
 			failures = append(failures, wf)
 		} else {
 			if verbose {
-				fmt.Fprintf(os.Stderr, "Disabled workflow: %s\n", wf)
+				fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Disabled workflow: %s", wf)))
 			}
 		}
 	}
diff --git a/pkg/cli/engine_secrets.go b/pkg/cli/engine_secrets.go
index a447a557f88..716b159742e 100644
--- a/pkg/cli/engine_secrets.go
+++ b/pkg/cli/engine_secrets.go
@@ -290,19 +290,19 @@ func promptForSecret(req SecretRequirement, config EngineSecretConfig) error {
 // promptForCopilotPATUnified prompts the user for a Copilot PAT with detailed instructions
 func promptForCopilotPATUnified(req SecretRequirement, config EngineSecretConfig) error {
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "GitHub Copilot requires a fine-grained Personal Access Token (PAT) with 'Copilot requests' permissions.")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("GitHub Copilot requires a fine-grained Personal Access Token (PAT) with 'Copilot requests' permissions."))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "Please create a token at:")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please create a token at:"))
 	fmt.Fprintln(os.Stderr, console.FormatCommandMessage("  "+req.KeyURL))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "Configure the token with:")
-	fmt.Fprintln(os.Stderr, "  • Token name: Agentic Workflows Copilot")
-	fmt.Fprintln(os.Stderr, "  • Expiration: 90 days (recommended for testing)")
-	fmt.Fprintln(os.Stderr, "  • Resource owner: Your personal account")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Configure the token with:"))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  • Token name: Agentic Workflows Copilot"))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  • Expiration: 90 days (recommended for testing)"))
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  • Resource owner: Your personal account"))
 	fmt.Fprintln(os.Stderr, "  • Repository access: \"Public repositories\" (you must use this setting for Copilot Requests permission to appear)")
-	fmt.Fprintln(os.Stderr, "  • Add permissions → Copilot Requests: Read-only")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  • Add permissions → Copilot Requests: Read-only"))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "If you run into trouble see https://github.github.com/gh-aw/reference/auth/#copilot_github_token.")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("If you run into trouble see https://github.github.com/gh-aw/reference/auth/#copilot_github_token."))
 
 	var token string
 	form := huh.NewForm(
@@ -343,12 +343,12 @@ func promptForSystemTokenUnified(req SecretRequirement, config EngineSecretConfi
 	engineSecretsLog.Printf("Prompting for system token: %s", req.Name)
 
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintf(os.Stderr, "%s requires a GitHub Personal Access Token (PAT).\n", req.Name)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("%s requires a GitHub Personal Access Token (PAT).", req.Name)))
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("When needed: "+req.WhenNeeded))
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Recommended scopes: "+req.Description))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "Create a token at:")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Create a token at:"))
 	fmt.Fprintln(os.Stderr, console.FormatCommandMessage("  https://github.com/settings/personal-access-tokens/new"))
 	fmt.Fprintln(os.Stderr, "")
 
@@ -397,10 +397,10 @@ func promptForGenericAPIKeyUnified(req SecretRequirement, config EngineSecretCon
 	}
 
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintf(os.Stderr, "%s requires an API key.\n", label)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("%s requires an API key.", label)))
 	fmt.Fprintln(os.Stderr, "")
 	if req.KeyURL != "" {
-		fmt.Fprintln(os.Stderr, "Get your API key from:")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Get your API key from:"))
 		fmt.Fprintln(os.Stderr, console.FormatCommandMessage("  "+req.KeyURL))
 		fmt.Fprintln(os.Stderr, "")
 	}
@@ -683,7 +683,7 @@ func displaySecretsSummaryTable(requirements []SecretRequirement, existingSecret
 		nameWithPadding := fmt.Sprintf("%-*s", maxNameWidth, req.Name)
 
 		// Display the line
-		fmt.Fprintf(os.Stderr, "  %s %s - %s\n", statusLine, nameWithPadding, req.WhenNeeded)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s %s - %s", statusLine, nameWithPadding, req.WhenNeeded)))
 	}
 
 	fmt.Fprintln(os.Stderr, "")
diff --git a/pkg/cli/fix_command.go b/pkg/cli/fix_command.go
index 31706234ab5..6a7588ab90a 100644
--- a/pkg/cli/fix_command.go
+++ b/pkg/cli/fix_command.go
@@ -98,11 +98,11 @@ func listAvailableCodemods() error {
 
 	for _, codemod := range codemods {
 		fmt.Fprintf(os.Stderr, "  %s\n", console.FormatInfoMessage(codemod.Name))
-		fmt.Fprintf(os.Stderr, "    ID: %s\n", codemod.ID)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    ID: %s", codemod.ID)))
 		if codemod.IntroducedIn != "" {
-			fmt.Fprintf(os.Stderr, "    Introduced in: %s\n", codemod.IntroducedIn)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    Introduced in: %s", codemod.IntroducedIn)))
 		}
-		fmt.Fprintf(os.Stderr, "    %s\n", codemod.Description)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    %s", codemod.Description)))
 		fmt.Fprintln(os.Stderr, "")
 	}
 
@@ -241,12 +241,12 @@ func runFixCommand(workflowIDs []string, write bool, verbose bool, workflowDir s
 			// Output as agent prompt
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To fix these issues, run:"))
 			fmt.Fprintln(os.Stderr, "")
-			fmt.Fprintln(os.Stderr, "  gh aw fix --write")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  gh aw fix --write"))
 			fmt.Fprintln(os.Stderr, "")
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Or fix them individually:"))
 			fmt.Fprintln(os.Stderr, "")
 			for _, wf := range workflowsNeedingFixes {
-				fmt.Fprintf(os.Stderr, "  gh aw fix %s --write\n", strings.TrimSuffix(wf.File, ".md"))
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  gh aw fix %s --write", strings.TrimSuffix(wf.File, ".md"))))
 			}
 		} else {
 			fmt.Fprintf(os.Stderr, "%s\n", console.FormatInfoMessage("✓ No fixes needed"))
@@ -326,12 +326,12 @@ func processWorkflowFileWithInfo(filePath string, codemods []Codemod, write bool
 
 		fmt.Fprintf(os.Stderr, "%s\n", console.FormatSuccessMessage("✓ "+fileName))
 		for _, codemodName := range appliedCodemods {
-			fmt.Fprintf(os.Stderr, "    • %s\n", codemodName)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    • %s", codemodName)))
 		}
 	} else {
 		fmt.Fprintf(os.Stderr, "%s\n", console.FormatWarningMessage("⚠ "+fileName))
 		for _, codemodName := range appliedCodemods {
-			fmt.Fprintf(os.Stderr, "    • %s\n", codemodName)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("    • %s", codemodName)))
 		}
 	}
 
diff --git a/pkg/cli/interactive.go b/pkg/cli/interactive.go
index cd64f370aca..f469f3ec55f 100644
--- a/pkg/cli/interactive.go
+++ b/pkg/cli/interactive.go
@@ -289,7 +289,7 @@ func (b *InteractiveWorkflowBuilder) generateWorkflow(force bool) error {
 	}
 
 	interactiveLog.Printf("Workflow file created successfully: %s", destFile)
-	fmt.Fprintf(os.Stderr, "Created new workflow: %s\n", destFile)
+	fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("Created new workflow: %s", destFile)))
 	return nil
 }
 
diff --git a/pkg/cli/list_workflows_command.go b/pkg/cli/list_workflows_command.go
index 9c84fde9ce4..56887be08fe 100644
--- a/pkg/cli/list_workflows_command.go
+++ b/pkg/cli/list_workflows_command.go
@@ -93,7 +93,7 @@ func RunListWorkflows(repo, path, pattern string, verbose bool, jsonOutput bool,
 		// List workflows from remote repository
 		isRemote = true
 		if verbose && !jsonOutput {
-			fmt.Fprintf(os.Stderr, "Listing workflow files from %s\n", repo)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Listing workflow files from %s", repo)))
 		}
 		mdFiles, err = getRemoteWorkflowFiles(repo, path, verbose, jsonOutput)
 	} else {
@@ -101,7 +101,7 @@ func RunListWorkflows(repo, path, pattern string, verbose bool, jsonOutput bool,
 		if verbose && !jsonOutput {
 			fmt.Fprintf(os.Stderr, "Listing workflow files\n")
 			if pattern != "" {
-				fmt.Fprintf(os.Stderr, "Filtering by pattern: %s\n", pattern)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Filtering by pattern: %s", pattern)))
 			}
 		}
 		mdFiles, err = getMarkdownWorkflowFiles(path)
@@ -127,7 +127,7 @@ func RunListWorkflows(repo, path, pattern string, verbose bool, jsonOutput bool,
 	}
 
 	if verbose && !jsonOutput {
-		fmt.Fprintf(os.Stderr, "Found %d markdown workflow files\n", len(mdFiles))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d markdown workflow files", len(mdFiles))))
 	}
 
 	// Build workflow list
@@ -259,7 +259,7 @@ func getRemoteWorkflowFiles(repoSpec, workflowPath string, verbose bool, jsonOut
 	repo = repoParts[1]
 
 	if verbose && !jsonOutput {
-		fmt.Fprintf(os.Stderr, "Fetching workflow files from %s/%s@%s (path: %s)\n", owner, repo, ref, workflowPath)
+		fmt.Fprintln(os.Stderr, console.FormatProgressMessage(fmt.Sprintf("Fetching workflow files from %s/%s@%s (path: %s)", owner, repo, ref, workflowPath)))
 	}
 
 	// Use the parser package to list workflow files
diff --git a/pkg/cli/logs_github_rate_limit_usage.go b/pkg/cli/logs_github_rate_limit_usage.go
index 4ca46d188a7..e7d488cad6a 100644
--- a/pkg/cli/logs_github_rate_limit_usage.go
+++ b/pkg/cli/logs_github_rate_limit_usage.go
@@ -18,6 +18,7 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/constants"
 	"github.com/github/gh-aw/pkg/logger"
 )
@@ -259,7 +260,7 @@ func analyzeGitHubRateLimits(runDir string, verbose bool) (*GitHubRateLimitUsage
 
 	if verbose {
 		if info, err := os.Stat(filePath); err == nil {
-			fmt.Fprintf(os.Stderr, "  Found GitHub rate limits file: %s (%d bytes)\n", filepath.Base(filePath), info.Size())
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Found GitHub rate limits file: %s (%d bytes)", filepath.Base(filePath), info.Size())))
 		}
 	}
 
diff --git a/pkg/cli/mcp_config_file.go b/pkg/cli/mcp_config_file.go
index 6a771361ace..19c68181e7d 100644
--- a/pkg/cli/mcp_config_file.go
+++ b/pkg/cli/mcp_config_file.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"path/filepath"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 )
 
@@ -59,7 +60,7 @@ func ensureMCPConfig(verbose bool) error {
 			if string(existingJSON) == string(newJSON) {
 				mcpConfigLog.Print("Configuration is identical, skipping")
 				if verbose {
-					fmt.Fprintf(os.Stderr, "MCP server '%s' already configured in %s\n", ghAwServerName, mcpConfigPath)
+					fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("MCP server '%s' already configured in %s", ghAwServerName, mcpConfigPath)))
 				}
 				return nil
 			}
@@ -103,7 +104,7 @@ func renderMCPConfigUpdateInstructions(filePath, serverName string, serverConfig
 		"ℹ",
 		"Existing file detected: "+filePath)
 	fmt.Fprintln(os.Stderr)
-	fmt.Fprintln(os.Stderr, "To enable GitHub Copilot Agent MCP server integration, please add the following")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To enable GitHub Copilot Agent MCP server integration, please add the following"))
 	fmt.Fprintf(os.Stderr, "to the \"mcpServers\" section of your %s file:\n", filePath)
 	fmt.Fprintln(os.Stderr)
 
diff --git a/pkg/cli/mcp_inspect_inspector.go b/pkg/cli/mcp_inspect_inspector.go
index bdc02ff6fd8..00cafe45219 100644
--- a/pkg/cli/mcp_inspect_inspector.go
+++ b/pkg/cli/mcp_inspect_inspector.go
@@ -73,7 +73,7 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e
 		if len(mcpConfigs) > 0 {
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Found %d MCP server(s) in workflow:", len(mcpConfigs))))
 			for _, config := range mcpConfigs {
-				fmt.Fprintf(os.Stderr, "  • %s (%s)\n", config.Name, config.Type)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  • %s (%s)", config.Name, config.Type)))
 			}
 			fmt.Fprintln(os.Stderr)
 
@@ -155,22 +155,22 @@ func spawnMCPInspector(workflowFile string, serverFilter string, verbose bool) e
 
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Configuration details for MCP inspector:"))
 			for _, config := range mcpConfigs {
-				fmt.Fprintf(os.Stderr, "\n📡 %s (%s):\n", config.Name, config.Type)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\n📡 %s (%s):", config.Name, config.Type)))
 				switch config.Type {
 				case "stdio":
 					if config.Container != "" {
-						fmt.Fprintf(os.Stderr, "  Container: %s\n", config.Container)
+						fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Container: %s", config.Container)))
 					} else {
-						fmt.Fprintf(os.Stderr, "  Command: %s\n", config.Command)
+						fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Command: %s", config.Command)))
 						if len(config.Args) > 0 {
-							fmt.Fprintf(os.Stderr, "  Args: %s\n", strings.Join(config.Args, " "))
+							fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Args: %s", strings.Join(config.Args, " "))))
 						}
 					}
 				case "http":
-					fmt.Fprintf(os.Stderr, "  URL: %s\n", config.URL)
+					fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  URL: %s", config.URL)))
 				}
 				if len(config.Env) > 0 {
-					fmt.Fprintf(os.Stderr, "  Environment Variables: %v\n", config.Env)
+					fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Environment Variables: %v", config.Env)))
 				}
 			}
 			fmt.Fprintln(os.Stderr)
diff --git a/pkg/cli/mcp_inspect_list.go b/pkg/cli/mcp_inspect_list.go
index 102c925dc2e..c61c4ece1e2 100644
--- a/pkg/cli/mcp_inspect_list.go
+++ b/pkg/cli/mcp_inspect_list.go
@@ -59,9 +59,9 @@ func listWorkflowsWithMCP(workflowsDir string, verbose bool) error {
 	mcpInspectListLog.Printf("Found %d workflows with MCP servers", len(workflowsWithMCP))
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Workflows with MCP servers:"))
 	for _, workflow := range workflowsWithMCP {
-		fmt.Fprintf(os.Stderr, "  • %s\n", workflow)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  • %s", workflow)))
 	}
-	fmt.Fprintf(os.Stderr, "\nRun 'gh aw mcp inspect <workflow-name>' to inspect MCP servers in a specific workflow.\n")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\nRun 'gh aw mcp inspect <workflow-name>' to inspect MCP servers in a specific workflow."))
 
 	return nil
 }
diff --git a/pkg/cli/mcp_inspect_mcp.go b/pkg/cli/mcp_inspect_mcp.go
index ccaa6e41699..1e37c4fb172 100644
--- a/pkg/cli/mcp_inspect_mcp.go
+++ b/pkg/cli/mcp_inspect_mcp.go
@@ -443,7 +443,7 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) {
 		for i, tool := range info.Tools {
 			toolNames[i] = tool.Name
 		}
-		fmt.Fprintf(os.Stderr, "%s\n", strings.Join(toolNames, ", "))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(strings.Join(toolNames, ", ")))
 		return
 	}
 
@@ -456,23 +456,23 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) {
 	fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatSectionHeader("🛠️  Tool Details: "+foundTool.Name))
 
 	// Display basic information
-	fmt.Fprintf(os.Stderr, "📋 **Name:** %s\n", foundTool.Name)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("📋 **Name:** %s", foundTool.Name)))
 
 	// Show title if available and different from name
 	if foundTool.Title != "" && foundTool.Title != foundTool.Name {
-		fmt.Fprintf(os.Stderr, "📄 **Title:** %s\n", foundTool.Title)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("📄 **Title:** %s", foundTool.Title)))
 	}
 	if foundTool.Annotations != nil && foundTool.Annotations.Title != "" && foundTool.Annotations.Title != foundTool.Name && foundTool.Annotations.Title != foundTool.Title {
-		fmt.Fprintf(os.Stderr, "📄 **Annotation Title:** %s\n", foundTool.Annotations.Title)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("📄 **Annotation Title:** %s", foundTool.Annotations.Title)))
 	}
 
-	fmt.Fprintf(os.Stderr, "📝 **Description:** %s\n", foundTool.Description)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("📝 **Description:** %s", foundTool.Description)))
 
 	// Display allowance status
 	if isAllowed {
-		fmt.Fprintf(os.Stderr, "✅ **Status:** Allowed\n")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("✅ **Status:** Allowed"))
 	} else {
-		fmt.Fprintf(os.Stderr, "🚫 **Status:** Not allowed (add to 'allowed' list in workflow frontmatter)\n")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🚫 **Status:** Not allowed (add to 'allowed' list in workflow frontmatter)"))
 	}
 
 	// Display annotations if available
@@ -480,28 +480,28 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatSectionHeader("⚙️  Tool Attributes"))
 
 		if foundTool.Annotations.ReadOnlyHint {
-			fmt.Fprintf(os.Stderr, "🔒 **Read-only:** This tool does not modify its environment\n")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🔒 **Read-only:** This tool does not modify its environment"))
 		} else {
-			fmt.Fprintf(os.Stderr, "🔓 **Modifies environment:** This tool can make changes\n")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🔓 **Modifies environment:** This tool can make changes"))
 		}
 
 		if foundTool.Annotations.IdempotentHint {
-			fmt.Fprintf(os.Stderr, "🔄 **Idempotent:** Calling with same arguments has no additional effect\n")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🔄 **Idempotent:** Calling with same arguments has no additional effect"))
 		}
 
 		if foundTool.Annotations.DestructiveHint != nil {
 			if *foundTool.Annotations.DestructiveHint {
-				fmt.Fprintf(os.Stderr, "⚠️  **Destructive:** May perform destructive updates\n")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("⚠️  **Destructive:** May perform destructive updates"))
 			} else {
-				fmt.Fprintf(os.Stderr, "➕ **Additive:** Performs only additive updates\n")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("➕ **Additive:** Performs only additive updates"))
 			}
 		}
 
 		if foundTool.Annotations.OpenWorldHint != nil {
 			if *foundTool.Annotations.OpenWorldHint {
-				fmt.Fprintf(os.Stderr, "🌐 **Open world:** Interacts with external entities\n")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🌐 **Open world:** Interacts with external entities"))
 			} else {
-				fmt.Fprintf(os.Stderr, "🏠 **Closed world:** Domain of interaction is closed\n")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("🏠 **Closed world:** Domain of interaction is closed"))
 			}
 		}
 	}
@@ -510,9 +510,9 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) {
 	if foundTool.InputSchema != nil {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatSectionHeader("📥 Input Schema"))
 		if schemaJSON, err := json.MarshalIndent(foundTool.InputSchema, "", "  "); err == nil {
-			fmt.Fprintf(os.Stderr, "```json\n%s\n```\n", string(schemaJSON))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("```json\n%s\n```", string(schemaJSON))))
 		} else {
-			fmt.Fprintf(os.Stderr, "Error displaying input schema: %v\n", err)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Error displaying input schema: %v", err)))
 		}
 	} else {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("📥 No input schema defined"))
@@ -522,9 +522,9 @@ func displayDetailedToolInfo(info *parser.MCPServerInfo, toolName string) {
 	if foundTool.OutputSchema != nil {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatSectionHeader("📤 Output Schema"))
 		if schemaJSON, err := json.MarshalIndent(foundTool.OutputSchema, "", "  "); err == nil {
-			fmt.Fprintf(os.Stderr, "```json\n%s\n```\n", string(schemaJSON))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("```json\n%s\n```", string(schemaJSON))))
 		} else {
-			fmt.Fprintf(os.Stderr, "Error displaying output schema: %v\n", err)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Error displaying output schema: %v", err)))
 		}
 	} else {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("📤 No output schema defined"))
@@ -553,29 +553,29 @@ func displayToolAllowanceHint(info *parser.MCPServerInfo) {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("💡 To allow blocked tools, add them to your workflow frontmatter:"))
 
 		// Show the frontmatter syntax example
-		fmt.Fprintf(os.Stderr, "\n")
-		fmt.Fprintf(os.Stderr, "```yaml\n")
-		fmt.Fprintf(os.Stderr, "tools:\n")
-		fmt.Fprintf(os.Stderr, "  %s:\n", info.Config.Name)
-		fmt.Fprintf(os.Stderr, "    allowed:\n")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(""))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("```yaml"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("tools:"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s:", info.Config.Name)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    allowed:"))
 
 		// Add currently allowed tools first (if any)
 		for _, allowed := range info.Config.Allowed {
-			fmt.Fprintf(os.Stderr, "      - %s\n", allowed)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("      - %s", allowed)))
 		}
 
 		// Show first few blocked tools as examples (limit to 3 for readability)
 		exampleCount := min(len(blockedTools), 3)
 
 		for i := range exampleCount {
-			fmt.Fprintf(os.Stderr, "      - %s\n", blockedTools[i])
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("      - %s", blockedTools[i])))
 		}
 
 		if len(blockedTools) > 3 {
-			fmt.Fprintf(os.Stderr, "      # ... and %d more tools\n", len(blockedTools)-3)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("      # ... and %d more tools", len(blockedTools)-3)))
 		}
 
-		fmt.Fprintf(os.Stderr, "```\n")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("```"))
 
 		if len(blockedTools) > 3 {
 			fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("📋 All blocked tools: "+strings.Join(blockedTools, ", ")))
@@ -585,16 +585,16 @@ func displayToolAllowanceHint(info *parser.MCPServerInfo) {
 		fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("💡 All tools are currently allowed (no 'allowed' list specified)"))
 		if len(info.Tools) > 0 {
 			fmt.Fprintf(os.Stderr, "\n%s\n", console.FormatInfoMessage("To restrict tools, add an 'allowed' list to your workflow frontmatter:"))
-			fmt.Fprintf(os.Stderr, "\n")
-			fmt.Fprintf(os.Stderr, "```yaml\n")
-			fmt.Fprintf(os.Stderr, "tools:\n")
-			fmt.Fprintf(os.Stderr, "  %s:\n", info.Config.Name)
-			fmt.Fprintf(os.Stderr, "    allowed:\n")
-			fmt.Fprintf(os.Stderr, "      - %s  # Allow only specific tools\n", info.Tools[0].Name)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(""))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("```yaml"))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("tools:"))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s:", info.Config.Name)))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    allowed:"))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("      - %s  # Allow only specific tools", info.Tools[0].Name)))
 			if len(info.Tools) > 1 {
-				fmt.Fprintf(os.Stderr, "      - %s\n", info.Tools[1].Name)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("      - %s", info.Tools[1].Name)))
 			}
-			fmt.Fprintf(os.Stderr, "```\n")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("```"))
 		}
 	} else {
 		// All tools are explicitly allowed
diff --git a/pkg/cli/mcp_list.go b/pkg/cli/mcp_list.go
index 5b9d78003da..ad66477cfc2 100644
--- a/pkg/cli/mcp_list.go
+++ b/pkg/cli/mcp_list.go
@@ -122,7 +122,7 @@ func ListWorkflowMCP(workflowFile string, verbose bool) error {
 	}
 
 	if !verbose {
-		fmt.Fprintf(os.Stderr, "\nRun 'gh aw mcp list %s --verbose' for detailed information\n", workflowFile)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\nRun 'gh aw mcp list %s --verbose' for detailed information", workflowFile)))
 	}
 
 	return nil
@@ -220,9 +220,9 @@ func listWorkflowsWithMCPServers(workflowsDir string, verbose bool) error {
 	}
 
 	if !verbose {
-		fmt.Fprintf(os.Stderr, "\nRun 'gh aw mcp list --verbose' for detailed information\n")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\nRun 'gh aw mcp list --verbose' for detailed information"))
 	}
-	fmt.Fprintf(os.Stderr, "Run 'gh aw mcp list <workflow-name>' to list MCP servers in a specific workflow\n")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Run 'gh aw mcp list <workflow-name>' to list MCP servers in a specific workflow"))
 
 	return nil
 }
diff --git a/pkg/cli/mcp_list_tools.go b/pkg/cli/mcp_list_tools.go
index 57f459496b9..97b60acf6ba 100644
--- a/pkg/cli/mcp_list_tools.go
+++ b/pkg/cli/mcp_list_tools.go
@@ -75,7 +75,7 @@ func ListToolsForMCP(workflowFile string, mcpServerName string, verbose bool) er
 		if len(mcpConfigs) > 0 {
 			fmt.Fprintf(os.Stderr, "Available MCP servers: ")
 			serverNames := sliceutil.Map(mcpConfigs, func(config parser.RegistryMCPServerConfig) string { return config.Name })
-			fmt.Fprintf(os.Stderr, "%s\n", strings.Join(serverNames, ", "))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(strings.Join(serverNames, ", ")))
 		}
 		return nil
 	}
@@ -132,7 +132,7 @@ func findWorkflowsWithMCPServer(workflowsDir string, mcpServerName string, verbo
 	// Display matching workflows and suggest using one
 	fmt.Fprintf(os.Stderr, "Found MCP server '%s' in %d workflow(s): %s\n",
 		mcpServerName, len(matchingWorkflows), strings.Join(matchingWorkflows, ", "))
-	fmt.Fprintf(os.Stderr, "\nRun 'gh aw mcp list-tools %s <workflow-name>' to list tools for a specific workflow\n", mcpServerName)
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\nRun 'gh aw mcp list-tools %s <workflow-name>' to list tools for a specific workflow", mcpServerName)))
 
 	return nil
 }
diff --git a/pkg/cli/observability_insights.go b/pkg/cli/observability_insights.go
index 1869a9c4517..412ab4c4d60 100644
--- a/pkg/cli/observability_insights.go
+++ b/pkg/cli/observability_insights.go
@@ -5,6 +5,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 )
 
@@ -342,10 +343,10 @@ func renderObservabilityInsights(insights []ObservabilityInsight) {
 			icon = "[low]"
 		}
 
-		fmt.Fprintf(os.Stderr, "  %s %s [%s]\n", icon, insight.Title, insight.Category)
-		fmt.Fprintf(os.Stderr, "     %s\n", insight.Summary)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s %s [%s]", icon, insight.Title, insight.Category)))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("     %s", insight.Summary)))
 		if strings.TrimSpace(insight.Evidence) != "" {
-			fmt.Fprintf(os.Stderr, "     Evidence: %s\n", insight.Evidence)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("     Evidence: %s", insight.Evidence)))
 		}
 		fmt.Fprintln(os.Stderr)
 	}
diff --git a/pkg/cli/preconditions.go b/pkg/cli/preconditions.go
index fd757f9b32e..9fec7562172 100644
--- a/pkg/cli/preconditions.go
+++ b/pkg/cli/preconditions.go
@@ -23,7 +23,7 @@ func checkGHAuthStatusShared(verbose bool) error {
 	if err != nil {
 		fmt.Fprintln(os.Stderr, console.FormatErrorMessage("You are not logged in to GitHub CLI."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "Please run the following command to authenticate:")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please run the following command to authenticate:"))
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatCommandMessage("  gh auth login"))
 		fmt.Fprintln(os.Stderr, "")
@@ -68,8 +68,8 @@ func checkActionsEnabledShared(repoSlug string, verbose bool) error {
 	if !permissions.Enabled {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage("GitHub Actions appears to be disabled for this repository."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "You can still add workflows, but they won't run until Actions is enabled.")
-		fmt.Fprintln(os.Stderr, "To enable GitHub Actions, go to Settings → Actions → General.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("You can still add workflows, but they won't run until Actions is enabled."))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To enable GitHub Actions, go to Settings → Actions → General."))
 		fmt.Fprintln(os.Stderr, "")
 		return nil
 	}
@@ -85,12 +85,12 @@ func checkActionsEnabledShared(repoSlug string, verbose bool) error {
 		// Only local actions allowed - this won't work for agentic workflows
 		fmt.Fprintln(os.Stderr, console.FormatErrorMessage("This repository only allows local actions (actions defined in this repository)."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "Agentic workflows require GitHub-owned actions to run.")
-		fmt.Fprintln(os.Stderr, "To allow this, go to Settings → Actions → General → Actions permissions")
-		fmt.Fprintln(os.Stderr, "and select 'Allow all actions' or 'Allow select actions' with GitHub-owned actions enabled.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Agentic workflows require GitHub-owned actions to run."))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To allow this, go to Settings → Actions → General → Actions permissions"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("and select 'Allow all actions' or 'Allow select actions' with GitHub-owned actions enabled."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "Note: For organization repositories, this setting may be controlled at the org level.")
-		fmt.Fprintln(os.Stderr, "Contact an organization owner if you cannot change this setting.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("For organization repositories, this setting may be controlled at the org level."))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Contact an organization owner if you cannot change this setting."))
 		fmt.Fprintln(os.Stderr, "")
 		return errors.New("repository action permissions prevent agentic workflows from running")
 	case "selected":
@@ -137,12 +137,12 @@ func checkSelectedActionsPermissions(selectedActionsURL string, verbose bool) er
 	if !selectedActions.GitHubOwnedAllowed {
 		fmt.Fprintln(os.Stderr, console.FormatErrorMessage("This repository does not allow GitHub-owned actions."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "Agentic workflows require GitHub-owned actions (like actions/checkout) to run.")
-		fmt.Fprintln(os.Stderr, "To allow this, go to Settings → Actions → General → Actions permissions")
-		fmt.Fprintln(os.Stderr, "and enable 'Allow actions created by GitHub'.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Agentic workflows require GitHub-owned actions (like actions/checkout) to run."))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To allow this, go to Settings → Actions → General → Actions permissions"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("and enable 'Allow actions created by GitHub'."))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "Note: For organization repositories, this setting may be controlled at the org level.")
-		fmt.Fprintln(os.Stderr, "Contact an organization owner if you cannot change this setting.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("For organization repositories, this setting may be controlled at the org level."))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Contact an organization owner if you cannot change this setting."))
 		fmt.Fprintln(os.Stderr, "")
 		return errors.New("GitHub-owned actions are not allowed in this repository")
 	}
@@ -183,7 +183,7 @@ func checkUserPermissionsShared(repoSlug string, verbose bool) (bool, error) {
 	if !hasAccess {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("You do not have write access to %s/%s.", owner, repo)))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintln(os.Stderr, "You can still add workflows, but you'll need to propose changes via pull requests.")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("You can still add workflows, but you'll need to propose changes via pull requests."))
 		fmt.Fprintln(os.Stderr, "")
 	} else if verbose {
 		fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("Repository permissions verified"))
diff --git a/pkg/cli/remove_command.go b/pkg/cli/remove_command.go
index 14a08b3391b..59d02298262 100644
--- a/pkg/cli/remove_command.go
+++ b/pkg/cli/remove_command.go
@@ -55,7 +55,7 @@ func RemoveWorkflows(pattern string, keepOrphans bool, workflowDir string) error
 			if workflowName != "" {
 				fmt.Fprintf(os.Stderr, "  %-20s - %s\n", name, workflowName)
 			} else {
-				fmt.Fprintf(os.Stderr, "  %s\n", name)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s", name)))
 			}
 		}
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("\nUsage: %s remove <filter>", string(constants.CLIExtensionPrefix))))
@@ -99,15 +99,15 @@ func RemoveWorkflows(pattern string, keepOrphans bool, workflowDir string) error
 	for _, file := range filesToRemove {
 		workflowName, _ := extractWorkflowNameFromFile(file)
 		if workflowName != "" {
-			fmt.Fprintf(os.Stderr, "  %s - %s\n", filepath.Base(file), workflowName)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s - %s", filepath.Base(file), workflowName)))
 		} else {
-			fmt.Fprintf(os.Stderr, "  %s\n", filepath.Base(file))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s", filepath.Base(file))))
 		}
 
 		// Also check for corresponding .lock.yml file in .github/workflows
 		lockFile := stringutil.MarkdownToLockFile(file)
 		if _, err := os.Stat(lockFile); err == nil {
-			fmt.Fprintf(os.Stderr, "  %s (compiled workflow)\n", filepath.Base(lockFile))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s (compiled workflow)", filepath.Base(lockFile))))
 		}
 	}
 
@@ -115,7 +115,7 @@ func RemoveWorkflows(pattern string, keepOrphans bool, workflowDir string) error
 	if len(orphanedIncludes) > 0 {
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\nThe following orphaned include files will also be removed (suppress with --keep-orphans):"))
 		for _, include := range orphanedIncludes {
-			fmt.Fprintf(os.Stderr, "  %s (orphaned include)\n", include)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s (orphaned include)", include)))
 		}
 	}
 
diff --git a/pkg/cli/run_interactive.go b/pkg/cli/run_interactive.go
index 2ce10d7c857..1d03e172810 100644
--- a/pkg/cli/run_interactive.go
+++ b/pkg/cli/run_interactive.go
@@ -118,7 +118,7 @@ func findRunnableWorkflows(verbose bool) ([]WorkflowOption, error) {
 	}
 
 	if verbose {
-		fmt.Fprintf(os.Stderr, "Found %d workflow files, checking for workflow_dispatch trigger...\n", len(mdFiles))
+		fmt.Fprintln(os.Stderr, console.FormatProgressMessage(fmt.Sprintf("Found %d workflow files, checking for workflow_dispatch trigger...", len(mdFiles))))
 	}
 
 	var runnableWorkflows []WorkflowOption
@@ -210,9 +210,9 @@ func selectWorkflow(ctx context.Context, workflows []WorkflowOption) (*WorkflowO
 func selectWorkflowNonInteractive(workflows []WorkflowOption) (*WorkflowOption, error) {
 	runInteractiveLog.Printf("Non-TTY detected, showing text list: %d workflows", len(workflows))
 
-	fmt.Fprintf(os.Stderr, "\nSelect a workflow to run:\n\n")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("\nSelect a workflow to run:\n"))
 	for i, wf := range workflows {
-		fmt.Fprintf(os.Stderr, "  %d) %s\n", i+1, wf.Name)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %d) %s", i+1, wf.Name)))
 	}
 	fmt.Fprintf(os.Stderr, "\nSelect (1-%d): ", len(workflows))
 
@@ -251,7 +251,7 @@ func showWorkflowInfo(wf *WorkflowOption) {
 			if input.Default != "" {
 				defaultVal = fmt.Sprintf(" [default: %s]", input.Default)
 			}
-			fmt.Fprintf(os.Stderr, "  • %s%s%s%s\n", name, required, desc, defaultVal)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  • %s%s%s%s", name, required, desc, defaultVal)))
 		}
 	}
 	fmt.Fprintln(os.Stderr, "")
diff --git a/pkg/cli/run_push.go b/pkg/cli/run_push.go
index 2ffd446d025..a3dd50056e6 100644
--- a/pkg/cli/run_push.go
+++ b/pkg/cli/run_push.go
@@ -416,7 +416,7 @@ func pushWorkflowFiles(workflowName string, files []string, refOverride string,
 	if verbose {
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Staging %d files for commit", len(files))))
 		for _, file := range files {
-			fmt.Fprintf(os.Stderr, "  - %s\n", file)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  - %s", file)))
 		}
 	}
 
@@ -535,7 +535,7 @@ func pushWorkflowFiles(workflowName string, files []string, refOverride string,
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Extra staged files:"))
 		for _, file := range extraStagedFiles {
-			fmt.Fprintf(os.Stderr, "  - %s\n", file)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  - %s", file)))
 		}
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please commit or unstage these files before using --push"))
@@ -553,7 +553,7 @@ func pushWorkflowFiles(workflowName string, files []string, refOverride string,
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Ready to commit and push the following files:"))
 	for _, file := range files {
-		fmt.Fprintf(os.Stderr, "  - %s\n", file)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  - %s", file)))
 	}
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintf(os.Stderr, console.FormatInfoMessage("Commit message: %s\n"), commitMessage)
diff --git a/pkg/cli/secret_set_command.go b/pkg/cli/secret_set_command.go
index 11c379fe2e8..86e4b9a7c3d 100644
--- a/pkg/cli/secret_set_command.go
+++ b/pkg/cli/secret_set_command.go
@@ -163,7 +163,7 @@ func resolveSecretValueForSet(fromEnv, fromFlag string) (string, error) {
 	// Fallback to non-interactive stdin reading (piped input or non-TTY)
 	secretSetLog.Print("Using non-interactive stdin reading")
 	if isTerminal {
-		fmt.Fprintln(os.Stderr, "Enter secret value, then press Ctrl+D:")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Enter secret value, then press Ctrl+D:"))
 	}
 
 	reader := io.Reader(os.Stdin)
diff --git a/pkg/cli/shell_completion.go b/pkg/cli/shell_completion.go
index 62ad66d3c7b..96e9d7bc067 100644
--- a/pkg/cli/shell_completion.go
+++ b/pkg/cli/shell_completion.go
@@ -289,8 +289,8 @@ func installZshCompletion(verbose bool, cmd *cobra.Command) error {
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To enable completions, add the following to your ~/.zshrc:"))
 		fmt.Fprintln(os.Stderr, "")
-		fmt.Fprintf(os.Stderr, "  fpath=(~/.zsh/completions $fpath)\n")
-		fmt.Fprintf(os.Stderr, "  autoload -Uz compinit && compinit\n")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  fpath=(~/.zsh/completions $fpath)"))
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  autoload -Uz compinit && compinit"))
 		fmt.Fprintln(os.Stderr, "")
 		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Then restart your shell or run: source ~/.zshrc"))
 	} else {
@@ -363,14 +363,14 @@ func installPowerShellCompletion(verbose bool, cmd *cobra.Command) error {
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To enable completions, add the following to your PowerShell profile:"))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "  gh aw completion powershell | Out-String | Invoke-Expression")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  gh aw completion powershell | Out-String | Invoke-Expression"))
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Or run the following command to append it automatically:"))
 	fmt.Fprintln(os.Stderr, "")
 	if runtime.GOOS == "windows" {
-		fmt.Fprintln(os.Stderr, "  gh aw completion powershell >> $PROFILE")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  gh aw completion powershell >> $PROFILE"))
 	} else {
-		fmt.Fprintln(os.Stderr, "  echo 'gh aw completion powershell | Out-String | Invoke-Expression' >> $PROFILE")
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  echo 'gh aw completion powershell | Out-String | Invoke-Expression' >> $PROFILE"))
 	}
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Then restart your shell or run: . $PROFILE"))
@@ -547,7 +547,7 @@ func uninstallPowerShellCompletion(verbose bool) error {
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("To uninstall completions, remove the following line from your PowerShell profile:"))
 	fmt.Fprintln(os.Stderr, "")
-	fmt.Fprintln(os.Stderr, "  gh aw completion powershell | Out-String | Invoke-Expression")
+	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  gh aw completion powershell | Out-String | Invoke-Expression"))
 	fmt.Fprintln(os.Stderr, "")
 	fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Then restart your shell or run: . $PROFILE"))
 
diff --git a/pkg/cli/token_usage.go b/pkg/cli/token_usage.go
index 550e9d2056d..03fcc1d0e65 100644
--- a/pkg/cli/token_usage.go
+++ b/pkg/cli/token_usage.go
@@ -10,6 +10,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 	"github.com/github/gh-aw/pkg/timeutil"
 	"github.com/github/gh-aw/pkg/types"
@@ -385,7 +386,7 @@ func analyzeTokenUsage(runDir string, verbose bool) (*TokenUsageSummary, error)
 		if verbose {
 			fileInfo, _ := os.Stat(filePath)
 			if fileInfo != nil {
-				fmt.Fprintf(os.Stderr, "  Found token usage file: %s (%d bytes)\n", filepath.Base(filePath), fileInfo.Size())
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Found token usage file: %s (%d bytes)", filepath.Base(filePath), fileInfo.Size())))
 			}
 		}
 
@@ -401,7 +402,7 @@ func analyzeTokenUsage(runDir string, verbose bool) (*TokenUsageSummary, error)
 	if verbose {
 		fileInfo, _ := os.Stat(agentUsagePath)
 		if fileInfo != nil {
-			fmt.Fprintf(os.Stderr, "  Found agent usage file: %s (%d bytes)\n", filepath.Base(agentUsagePath), fileInfo.Size())
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Found agent usage file: %s (%d bytes)", filepath.Base(agentUsagePath), fileInfo.Size())))
 		}
 	}
 
diff --git a/pkg/cli/trial_confirmation.go b/pkg/cli/trial_confirmation.go
index 112860f8da1..c77857c6ae2 100644
--- a/pkg/cli/trial_confirmation.go
+++ b/pkg/cli/trial_confirmation.go
@@ -165,8 +165,8 @@ func showTrialConfirmation(parsedSpecs []*WorkflowSpec, logicalRepoSlug, cloneRe
 		workflowName := parsedSpecs[0].WorkflowName
 		if repeatCount > 0 && autoMergePRs {
 			fmt.Fprintf(os.Stderr, console.FormatInfoMessage("  %d. For each of %d executions:\n"), stepNum, repeatCount+1)
-			fmt.Fprintf(os.Stderr, "     a. Execute %s\n", workflowName)
-			fmt.Fprintf(os.Stderr, "     b. Auto-merge any pull requests created during execution\n")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("     a. Execute %s", workflowName)))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     b. Auto-merge any pull requests created during execution"))
 		} else if repeatCount > 0 {
 			fmt.Fprintf(os.Stderr, console.FormatInfoMessage("  %d. Execute %s %d times\n"), stepNum, workflowName, repeatCount+1)
 		} else if autoMergePRs {
@@ -182,8 +182,8 @@ func showTrialConfirmation(parsedSpecs []*WorkflowSpec, logicalRepoSlug, cloneRe
 
 		if repeatCount > 0 && autoMergePRs {
 			fmt.Fprintf(os.Stderr, console.FormatInfoMessage("  %d. For each of %d executions:\n"), stepNum, repeatCount+1)
-			fmt.Fprintf(os.Stderr, "     a. Execute: %s\n", workflowList)
-			fmt.Fprintf(os.Stderr, "     b. Auto-merge any pull requests created during execution\n")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("     a. Execute: %s", workflowList)))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("     b. Auto-merge any pull requests created during execution"))
 		} else if repeatCount > 0 {
 			fmt.Fprintf(os.Stderr, console.FormatInfoMessage("  %d. Execute %d times: %s\n"), stepNum, repeatCount+1, workflowList)
 		} else if autoMergePRs {
diff --git a/pkg/cli/update_actions.go b/pkg/cli/update_actions.go
index c29dbd36e75..b6792114eab 100644
--- a/pkg/cli/update_actions.go
+++ b/pkg/cli/update_actions.go
@@ -182,7 +182,7 @@ func UpdateActions(ctx context.Context, allowMajor, verbose, disableReleaseBump
 	if len(failedActions) > 0 {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to check %d action(s):", len(failedActions))))
 		for _, f := range failedActions {
-			fmt.Fprintf(os.Stderr, "  %s: %s\n", f.name, f.err)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s: %s", f.name, f.err)))
 		}
 		fmt.Fprintln(os.Stderr, "")
 	}
diff --git a/pkg/cli/update_container_pins.go b/pkg/cli/update_container_pins.go
index 594172944a7..933af8165ad 100644
--- a/pkg/cli/update_container_pins.go
+++ b/pkg/cli/update_container_pins.go
@@ -147,7 +147,7 @@ func UpdateContainerPins(ctx context.Context, workflowDir string, verbose bool)
 	if len(failedImages) > 0 {
 		fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Failed to resolve digest for %d image(s) (Docker/crane may be unavailable):", len(failedImages))))
 		for _, f := range failedImages {
-			fmt.Fprintf(os.Stderr, "  %s: %s\n", f.image, f.reason)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s: %s", f.image, f.reason)))
 		}
 		fmt.Fprintln(os.Stderr, "")
 	}
@@ -307,7 +307,7 @@ func resolveDigestViaCrane(ctx context.Context, image string) (string, error) {
 // resolveDigestViaPull pulls the image and then reads its RepoDigests field.
 func resolveDigestViaPull(ctx context.Context, image string, verbose bool) (string, error) {
 	if verbose {
-		fmt.Fprintf(os.Stderr, "  Pulling %s to resolve digest...\n", image)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  Pulling %s to resolve digest...", image)))
 	}
 
 	pullCtx, pullCancel := context.WithTimeout(ctx, dockerCmdTimeout)
diff --git a/pkg/cli/update_display.go b/pkg/cli/update_display.go
index b16833bb5e6..55ba5874e78 100644
--- a/pkg/cli/update_display.go
+++ b/pkg/cli/update_display.go
@@ -24,7 +24,7 @@ func showUpdateSummary(successfulUpdates []string, failedUpdates []updateFailure
 	if len(failedUpdates) > 0 {
 		fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("Failed to update %d workflow(s):", len(failedUpdates))))
 		for _, failure := range failedUpdates {
-			fmt.Fprintf(os.Stderr, "  %s: %s\n", failure.Name, failure.Error)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("  %s: %s", failure.Name, failure.Error)))
 		}
 		fmt.Fprintln(os.Stderr, "")
 	}
diff --git a/pkg/cli/update_extension_check.go b/pkg/cli/update_extension_check.go
index 9a745f8e068..49d6a637f6c 100644
--- a/pkg/cli/update_extension_check.go
+++ b/pkg/cli/update_extension_check.go
@@ -186,9 +186,9 @@ func upgradeExtensionIfOutdated(verbose bool, includePrereleases bool) (bool, st
 			// running. Guide the user to upgrade manually from a separate shell.
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("On Windows, gh-aw cannot self-upgrade while it is running."))
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Please upgrade manually by running one of the following:"))
-			fmt.Fprintln(os.Stderr, "  gh extension upgrade gh-aw")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  gh extension upgrade gh-aw"))
 			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("If that does not work, try reinstalling:"))
-			fmt.Fprintln(os.Stderr, "  gh extension remove gh-aw")
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  gh extension remove gh-aw"))
 			fmt.Fprintln(os.Stderr, "  gh extension install "+extensionRepo)
 		}
 		return false, "", fmt.Errorf("failed to upgrade gh-aw extension: %w", retryErr)
diff --git a/pkg/cli/vscode_config.go b/pkg/cli/vscode_config.go
index 511223565f5..851cfc9a95e 100644
--- a/pkg/cli/vscode_config.go
+++ b/pkg/cli/vscode_config.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"path/filepath"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 )
 
@@ -77,7 +78,7 @@ func ensureVSCodeSettings(verbose bool) error {
 	if _, err := os.Stat(settingsPath); err == nil {
 		vscodeConfigLog.Print("Settings file already exists, skipping creation")
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Settings file already exists at %s\n", settingsPath)
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Settings file already exists at %s", settingsPath)))
 		}
 		return nil
 	}
diff --git a/pkg/workflow/action_sha_checker.go b/pkg/workflow/action_sha_checker.go
index e4ed3ae144f..bb1c510b21c 100644
--- a/pkg/workflow/action_sha_checker.go
+++ b/pkg/workflow/action_sha_checker.go
@@ -183,8 +183,8 @@ func ValidateActionSHAsInLockFile(lockFilePath string, cache *ActionCache, verbo
 
 			// Show full SHA in verbose mode
 			if verbose {
-				fmt.Fprintf(os.Stderr, "    Current: %s\n", check.Action.SHA)
-				fmt.Fprintf(os.Stderr, "    Latest:  %s\n", check.LatestSHA)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    Current: "+check.Action.SHA))
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("    Latest:  "+check.LatestSHA))
 			}
 		}
 	}
diff --git a/pkg/workflow/cache.go b/pkg/workflow/cache.go
index e9e0e107777..df5aa23b06d 100644
--- a/pkg/workflow/cache.go
+++ b/pkg/workflow/cache.go
@@ -8,6 +8,7 @@ import (
 	"sort"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/constants"
 	"github.com/github/gh-aw/pkg/logger"
 	"github.com/goccy/go-yaml"
@@ -335,7 +336,7 @@ func generateCacheSteps(builder *strings.Builder, data *WorkflowData, verbose bo
 	var topLevel map[string]any
 	if err := yaml.Unmarshal([]byte(data.Cache), &topLevel); err != nil {
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Warning: Failed to parse cache configuration: %v\n", err)
+			fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("Warning: Failed to parse cache configuration: %v", err)))
 		}
 		return
 	}
@@ -344,7 +345,7 @@ func generateCacheSteps(builder *strings.Builder, data *WorkflowData, verbose bo
 	cacheConfig, exists := topLevel["cache"]
 	if !exists {
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Warning: No cache key found in parsed configuration\n")
+			fmt.Fprintln(os.Stderr, console.FormatWarningMessage("No cache key found in parsed configuration"))
 		}
 		return
 	}
diff --git a/pkg/workflow/claude_logs.go b/pkg/workflow/claude_logs.go
index 2526ba9edd9..cb6d66871f5 100644
--- a/pkg/workflow/claude_logs.go
+++ b/pkg/workflow/claude_logs.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 	"github.com/github/gh-aw/pkg/typeutil"
 )
@@ -152,7 +153,7 @@ func (e *ClaudeEngine) parseClaudeJSONLog(logContent string, verbose bool) LogMe
 		// If that fails, try to parse as mixed format (debug logs + JSONL)
 		claudeLogsLog.Print("JSON array parse failed, trying JSONL format")
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Failed to parse Claude log as JSON array, trying JSONL format: %v\n", err)
+			fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("Failed to parse Claude log as JSON array, trying JSONL format: %v", err)))
 		}
 
 		logEntries = []map[string]any{}
@@ -213,7 +214,7 @@ func (e *ClaudeEngine) parseClaudeJSONLog(logContent string, verbose bool) LogMe
 			if err := json.Unmarshal([]byte(trimmedLine), &jsonEntry); err != nil {
 				// Skip invalid JSON lines (could be partial debug output)
 				if verbose {
-					fmt.Fprintf(os.Stderr, "Skipping invalid JSON line: %s\n", trimmedLine)
+					fmt.Fprintln(os.Stderr, console.FormatInfoMessage("Skipping invalid JSON line: "+trimmedLine))
 				}
 				continue
 			}
@@ -223,13 +224,13 @@ func (e *ClaudeEngine) parseClaudeJSONLog(logContent string, verbose bool) LogMe
 
 		if len(logEntries) == 0 {
 			if verbose {
-				fmt.Fprintf(os.Stderr, "No valid JSON entries found in Claude log\n")
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage("No valid JSON entries found in Claude log"))
 			}
 			return metrics
 		}
 
 		if verbose {
-			fmt.Fprintf(os.Stderr, "Extracted %d JSON entries from mixed format Claude log\n", len(logEntries))
+			fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Extracted %d JSON entries from mixed format Claude log", len(logEntries))))
 		}
 	}
 
diff --git a/pkg/workflow/compiler_orchestrator_engine.go b/pkg/workflow/compiler_orchestrator_engine.go
index 6d47c6ebfb8..9e1bb1001ff 100644
--- a/pkg/workflow/compiler_orchestrator_engine.go
+++ b/pkg/workflow/compiler_orchestrator_engine.go
@@ -168,13 +168,13 @@ func (c *Compiler) setupEngineAndImports(result *parser.FrontmatterResult, clean
 		fullPath, resolveErr := parser.ResolveIncludePath(importFilePath, markdownDir, importCache)
 		if resolveErr != nil {
 			orchestratorEngineLog.Printf("Skipping security scan for unresolvable import: %s: %v", importedFile, resolveErr)
-			fmt.Fprintf(os.Stderr, "WARNING: Skipping security scan for unresolvable import '%s': %v\n", importedFile, resolveErr)
+			fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Skipping security scan for unresolvable import '%s': %v", importedFile, resolveErr)))
 			continue
 		}
 		importContent, readErr := parser.ReadFile(fullPath)
 		if readErr != nil {
 			orchestratorEngineLog.Printf("Skipping security scan for unreadable import: %s: %v", fullPath, readErr)
-			fmt.Fprintf(os.Stderr, "WARNING: Skipping security scan for unreadable import '%s' (resolved path: %s): %v\n", importedFile, fullPath, readErr)
+			fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Skipping security scan for unreadable import '%s' (resolved path: %s): %v", importedFile, fullPath, readErr)))
 			continue
 		}
 		if findings := ScanMarkdownSecurity(string(importContent)); len(findings) > 0 {
diff --git a/pkg/workflow/mcp_renderer.go b/pkg/workflow/mcp_renderer.go
index ad9efaa1dd2..5b3c1a6fdeb 100644
--- a/pkg/workflow/mcp_renderer.go
+++ b/pkg/workflow/mcp_renderer.go
@@ -49,6 +49,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 )
 
@@ -86,7 +87,7 @@ func HandleCustomMCPToolInSwitch(
 	if toolConfig, ok := tools[toolName].(map[string]any); ok {
 		if hasMcp, _ := hasMCPConfig(toolConfig); hasMcp {
 			if err := renderFunc(yaml, toolName, toolConfig, isLast); err != nil {
-				fmt.Fprintf(os.Stderr, "Error generating custom MCP configuration for %s: %v\n", toolName, err)
+				fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("Error generating custom MCP configuration for %s: %v", toolName, err)))
 			}
 			return true
 		}
diff --git a/pkg/workflow/push_to_pull_request_branch.go b/pkg/workflow/push_to_pull_request_branch.go
index bc58b6b50cf..387b29f4a42 100644
--- a/pkg/workflow/push_to_pull_request_branch.go
+++ b/pkg/workflow/push_to_pull_request_branch.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"os"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/logger"
 )
 
@@ -109,7 +110,7 @@ func (c *Compiler) parsePushToPullRequestBranchConfig(outputMap map[string]any)
 					default:
 						// Invalid value, use default and log warning
 						if c.verbose {
-							fmt.Fprintf(os.Stderr, "Warning: invalid if-no-changes value '%s', using default 'warn'\n", ifNoChangesStr)
+							fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("invalid if-no-changes value '%s', using default 'warn'", ifNoChangesStr)))
 						}
 						pushToBranchConfig.IfNoChanges = "warn"
 					}
diff --git a/pkg/workflow/side_repo_maintenance.go b/pkg/workflow/side_repo_maintenance.go
index 40870864e1e..152eade1f24 100644
--- a/pkg/workflow/side_repo_maintenance.go
+++ b/pkg/workflow/side_repo_maintenance.go
@@ -7,6 +7,7 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/github/gh-aw/pkg/console"
 	"github.com/github/gh-aw/pkg/stringutil"
 )
 
@@ -106,7 +107,7 @@ func generateAllSideRepoMaintenanceWorkflows(
 		if err := generateSideRepoMaintenanceWorkflow(target, outPath, version, actionMode, actionTag, runsOnValue, resolver, hasExpires, minExpiresDays); err != nil {
 			return fmt.Errorf("failed to generate side-repo maintenance workflow for %s: %w", target.Repository, err)
 		}
-		fmt.Fprintf(os.Stderr, "  Generated side-repo maintenance workflow: %s\n", filename)
+		fmt.Fprintln(os.Stderr, console.FormatInfoMessage("  Generated side-repo maintenance workflow: "+filename))
 	}
 
 	// Remove stale side-repo maintenance workflows that are no longer referenced.
@@ -130,7 +131,7 @@ func generateAllSideRepoMaintenanceWorkflows(
 		if err := os.Remove(stalePath); err != nil {
 			return fmt.Errorf("failed to remove stale side-repo maintenance workflow %s: %w", stalePath, err)
 		}
-		fmt.Fprintf(os.Stderr, "  Removed stale side-repo maintenance workflow: %s\n", name)
+		fmt.Fprintln(os.Stderr, console.FormatSuccessMessage("  Removed stale side-repo maintenance workflow: "+name))
 	}
 
 	return nil
diff --git a/process_file.py b/process_file.py
new file mode 100755
index 00000000000..4f813572dbf
--- /dev/null
+++ b/process_file.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python3
+"""
+Script to migrate fmt.Fprintf/Fprintln(os.Stderr) calls to console helpers.
+This processes one file at a time and outputs the modified content.
+"""
+
+import re
+import sys
+
+def should_skip_conversion(line, prev_lines):
+    """Determine if this line should be skipped."""
+    # Skip blank lines
+    if 'fmt.Fprintln(os.Stderr, "")' in line or line.strip() == 'fmt.Fprintln(os.Stderr)':
+        return True
+    if 'fmt.Fprintf(os.Stderr, "\\n")' in line and 'fmt.Fprintf(os.Stderr, "\\n")' == line.strip():
+        return True
+    # Skip complex formatting with padding/alignment
+    if re.search(r'%-?\d+[sd]', line):
+        return True
+    # Skip if already using console.Format
+    if 'console.Format' in line:
+        return True
+    return False
+
+def determine_helper(message_content):
+    """Determine the appropriate console helper based on message content."""
+    msg_lower = message_content.lower()
+    
+    # Error patterns
+    if any(p in msg_lower for p in ['error:', 'failed', 'failure', 'cannot', 'unable', 'err.error()']):
+        return 'FormatErrorMessage'
+    
+    # Success patterns
+    if any(p in msg_lower for p in ['success', 'done!', 'complete', ' enabled', ' disabled', 'created', 'updated', 'removed']):
+        return 'FormatSuccessMessage'
+    
+    # Progress patterns (present continuous)
+    if any(p in msg_lower for p in ['downloading', 'processing', 'compiling', 'running', 'checking', 'fetching', 'loading', 'building', 'installing', 'analyzing', 'creating']):
+        return 'FormatProgressMessage'
+    
+    # Warning patterns
+    if any(p in msg_lower for p in ['warning:', 'note:', 'deprecated', 'caution']):
+        return 'FormatWarningMessage'
+    
+    # Command patterns
+    if 'gh aw ' in message_content or message_content.strip().startswith('`'):
+        return 'FormatCommandMessage'
+    
+    # List item (starts with spaces/indent)
+    if message_content.lstrip().startswith('  ') and not message_content.lstrip().startswith('   '):
+        return 'FormatListItem'
+    
+    # Default to info
+    return 'FormatInfoMessage'
+
+def clean_prefix(msg, helper):
+    """Remove redundant prefixes based on the helper."""
+    if helper == 'FormatErrorMessage':
+        msg = re.sub(r'^Error:\s*', '', msg, flags=re.IGNORECASE)
+        msg = re.sub(r'^Failed:\s*', '', msg, flags=re.IGNORECASE)
+    elif helper == 'FormatWarningMessage':
+        msg = re.sub(r'^Warning:\s*', '', msg, flags=re.IGNORECASE)
+        msg = re.sub(r'^Note:\s*', '', msg, flags=re.IGNORECASE)
+    elif helper == 'FormatSuccessMessage':
+        msg = re.sub(r'^Success:\s*', '', msg, flags=re.IGNORECASE)
+        msg = re.sub(r'^✓\s*', '', msg)
+    return msg
+
+def convert_fprintln(line):
+    """Convert fmt.Fprintln(os.Stderr, msg) to use console helper."""
+    # Pattern: fmt.Fprintln(os.Stderr, "literal message")
+    match = re.search(r'fmt\.Fprintln\(os\.Stderr,\s*"([^"]+)"\)', line)
+    if match:
+        msg = match.group(1)
+        helper = determine_helper(msg)
+        msg = clean_prefix(msg, helper)
+        # Remove \n if present at the end
+        msg = msg.rstrip('\\n')
+        replacement = f'fmt.Fprintln(os.Stderr, console.{helper}("{msg}"))'
+        return line.replace(match.group(0), replacement)
+    
+    # Pattern: fmt.Fprintln(os.Stderr, console.FormatXXX(...))
+    # Already converted, skip
+    if 'console.Format' in line:
+        return line
+    
+    return line
+
+def convert_fprintf(line):
+    """Convert fmt.Fprintf(os.Stderr, format, args...) to use console helper."""
+    # Simple pattern: fmt.Fprintf(os.Stderr, "message\n")
+    match = re.search(r'fmt\.Fprintf\(os\.Stderr,\s*"([^"]+)\\n"\)', line)
+    if match:
+        msg = match.group(1)
+        # Skip if it has format verbs
+        if '%' in msg:
+            return line
+        helper = determine_helper(msg)
+        msg = clean_prefix(msg, helper)
+        replacement = f'fmt.Fprintln(os.Stderr, console.{helper}("{msg}"))'
+        return line.replace(match.group(0), replacement)
+    
+    return line
+
+def process_file(content):
+    """Process file content and return modified version."""
+    lines = content.split('\n')
+    modified_lines = []
+    needs_console_import = False
+    has_console_import = False
+    
+    # Check if console is already imported
+    in_import_block = False
+    for line in lines:
+        if 'import (' in line:
+            in_import_block = True
+        elif in_import_block and ')' in line:
+            in_import_block = False
+        
+        if 'github.com/github/gh-aw/pkg/console' in line:
+            has_console_import = True
+            break
+    
+    for i, line in enumerate(lines):
+        prev_lines = lines[max(0, i-3):i]
+        
+        # Skip if shouldn't convert
+        if should_skip_conversion(line, prev_lines):
+            modified_lines.append(line)
+            continue
+        
+        # Try conversions
+        original = line
+        if 'fmt.Fprintln(os.Stderr' in line:
+            line = convert_fprintln(line)
+        elif 'fmt.Fprintf(os.Stderr' in line:
+            line = convert_fprintf(line)
+        
+        if line != original:
+            needs_console_import = True
+        
+        modified_lines.append(line)
+    
+    # Add console import if needed and not present
+    if needs_console_import and not has_console_import:
+        # Find import block and add console
+        for i, line in enumerate(modified_lines):
+            if 'import (' in line:
+                # Find a good place to insert (after other pkg imports)
+                j = i + 1
+                while j < len(modified_lines) and modified_lines[j].strip() and ')' not in modified_lines[j]:
+                    j += 1
+                # Insert before the closing paren or at the end of imports
+                insert_pos = j
+                for k in range(i+1, j):
+                    if 'github.com/github/gh-aw/pkg/' in modified_lines[k]:
+                        insert_pos = k + 1
+                modified_lines.insert(insert_pos, '\t"github.com/github/gh-aw/pkg/console"')
+                break
+    
+    return '\n'.join(modified_lines)
+
+if __name__ == '__main__':
+    if len(sys.argv) != 2:
+        print("Usage: process_file.py <filepath>", file=sys.stderr)
+        sys.exit(1)
+    
+    filepath = sys.argv[1]
+    with open(filepath, 'r') as f:
+        content = f.read()
+    
+    modified = process_file(content)
+    
+    with open(filepath, 'w') as f:
+        f.write(modified)
+    
+    print(f"Processed: {filepath}")
