From d28e67cf4238a115333c056e978b936ab144caeb Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 29 Mar 2026 21:18:51 +0000
Subject: [PATCH 1/4] Initial plan


From bc9bed3b8ba3d23ab0842e2a1b7870708bf687ee Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 29 Mar 2026 21:44:17 +0000
Subject: [PATCH 2/4] feat: add runs-on-activation frontmatter field for
 compile-stable framework job runner override
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Add a new top-level `runs-on-activation:` frontmatter field that provides a
compile-stable way to override the runner for all framework/generated jobs
(activation, pre-activation, safe-outputs, unlock, APM, etc.).

Precedence (highest to lowest):
1. safe-outputs.runs-on — existing per-section override (backward compat)
2. runs-on-activation   — new top-level field for all framework jobs
3. DefaultActivationJobRunnerImage — compiled-in default (ubuntu-slim)

This addresses the issue where teams on self-hosted or GHES environments
had to manually patch lock files after each recompile to restore the
runner for generated jobs. The new field persists across recompile as
it lives in the frontmatter source.

Changes:
- compiler_types.go: Add RunsOnActivation field to WorkflowData
- frontmatter_types.go: Add RunsOnActivation to FrontmatterConfig + ToMap()
- compiler_orchestrator_workflow.go: Extract runs-on-activation from frontmatter
- safe_outputs_runtime.go: Add formatFrameworkJobRunsOn() helper
- Update 6 job builders to use formatFrameworkJobRunsOn(data)
- Update JSON schema with runs-on-activation property
- Add tests: TestRunsOnActivationField, TestFormatFrameworkJobRunsOn

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/063d54f7-0f17-4023-82d4-e6efb33f5e0c

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/parser/schemas/main_workflow_schema.json  |   5 +
 pkg/workflow/compiler_activation_job.go       |   2 +-
 pkg/workflow/compiler_apm_job.go              |   2 +-
 .../compiler_orchestrator_workflow.go         |   6 +
 pkg/workflow/compiler_pre_activation_job.go   |   2 +-
 pkg/workflow/compiler_safe_outputs_job.go     |   2 +-
 pkg/workflow/compiler_types.go                |   1 +
 pkg/workflow/compiler_unlock_job.go           |   2 +-
 pkg/workflow/frontmatter_types.go             |  20 ++-
 pkg/workflow/notify_comment.go                |   2 +-
 pkg/workflow/safe_outputs_runs_on_test.go     | 162 ++++++++++++++++++
 pkg/workflow/safe_outputs_runtime.go          |  20 +++
 12 files changed, 212 insertions(+), 14 deletions(-)

diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json
index 80d4996f193..706140a3b20 100644
--- a/pkg/parser/schemas/main_workflow_schema.json
+++ b/pkg/parser/schemas/main_workflow_schema.json
@@ -2631,6 +2631,11 @@
         }
       ]
     },
+    "runs-on-activation": {
+      "type": "string",
+      "description": "Runner for all framework/generated jobs (activation, pre-activation, safe-outputs, unlock, APM, etc.). Provides a compile-stable override for generated job runners without requiring a safe-outputs section. Overridden by safe-outputs.runs-on when both are set. Defaults to 'ubuntu-slim'. Use this when your infrastructure does not provide the default runner or when you need consistent runner selection across all jobs.",
+      "examples": ["self-hosted", "ubuntu-latest", "ubuntu-22.04"]
+    },
     "timeout-minutes": {
       "type": "integer",
       "minimum": 1,
diff --git a/pkg/workflow/compiler_activation_job.go b/pkg/workflow/compiler_activation_job.go
index ba8a2b86f32..9aa41e81118 100644
--- a/pkg/workflow/compiler_activation_job.go
+++ b/pkg/workflow/compiler_activation_job.go
@@ -524,7 +524,7 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate
 		Name:                       string(constants.ActivationJobName),
 		If:                         activationCondition,
 		HasWorkflowRunSafetyChecks: workflowRunRepoSafety != "", // Mark job as having workflow_run safety checks
-		RunsOn:                     c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:                     c.formatFrameworkJobRunsOn(data),
 		Permissions:                permissions,
 		Environment:                environment,
 		Steps:                      steps,
diff --git a/pkg/workflow/compiler_apm_job.go b/pkg/workflow/compiler_apm_job.go
index 50f1c192224..5fb4b853436 100644
--- a/pkg/workflow/compiler_apm_job.go
+++ b/pkg/workflow/compiler_apm_job.go
@@ -82,7 +82,7 @@ func (c *Compiler) buildAPMJob(data *WorkflowData) (*Job, error) {
 
 	job := &Job{
 		Name:        string(constants.APMJobName),
-		RunsOn:      c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:      c.formatFrameworkJobRunsOn(data),
 		Permissions: c.indentYAMLLines(permissions, "    "),
 		Env:         env,
 		Steps:       steps,
diff --git a/pkg/workflow/compiler_orchestrator_workflow.go b/pkg/workflow/compiler_orchestrator_workflow.go
index 27705687863..39f71c036a6 100644
--- a/pkg/workflow/compiler_orchestrator_workflow.go
+++ b/pkg/workflow/compiler_orchestrator_workflow.go
@@ -253,6 +253,12 @@ func (c *Compiler) extractYAMLSections(frontmatter map[string]any, workflowData
 	workflowData.TimeoutMinutes = c.extractTopLevelYAMLSection(frontmatter, "timeout-minutes")
 
 	workflowData.RunsOn = c.extractTopLevelYAMLSection(frontmatter, "runs-on")
+	// Extract runs-on-activation as a plain string (no YAML formatting needed)
+	if v, ok := frontmatter["runs-on-activation"]; ok {
+		if s, ok := v.(string); ok {
+			workflowData.RunsOnActivation = s
+		}
+	}
 	workflowData.Environment = c.extractTopLevelYAMLSection(frontmatter, "environment")
 	workflowData.Container = c.extractTopLevelYAMLSection(frontmatter, "container")
 	workflowData.Cache = c.extractTopLevelYAMLSection(frontmatter, "cache")
diff --git a/pkg/workflow/compiler_pre_activation_job.go b/pkg/workflow/compiler_pre_activation_job.go
index ab6d2a53526..bbd91841a53 100644
--- a/pkg/workflow/compiler_pre_activation_job.go
+++ b/pkg/workflow/compiler_pre_activation_job.go
@@ -422,7 +422,7 @@ func (c *Compiler) buildPreActivationJob(data *WorkflowData, needsPermissionChec
 	job := &Job{
 		Name:        string(constants.PreActivationJobName),
 		If:          jobIfCondition,
-		RunsOn:      c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:      c.formatFrameworkJobRunsOn(data),
 		Environment: c.indentYAMLLines(resolveSafeOutputsEnvironment(data), "    "),
 		Permissions: permissions,
 		Steps:       steps,
diff --git a/pkg/workflow/compiler_safe_outputs_job.go b/pkg/workflow/compiler_safe_outputs_job.go
index 1edd6a799e0..52045664df6 100644
--- a/pkg/workflow/compiler_safe_outputs_job.go
+++ b/pkg/workflow/compiler_safe_outputs_job.go
@@ -430,7 +430,7 @@ func (c *Compiler) buildConsolidatedSafeOutputsJob(data *WorkflowData, mainJobNa
 	job := &Job{
 		Name:           "safe_outputs",
 		If:             RenderCondition(jobCondition),
-		RunsOn:         c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:         c.formatFrameworkJobRunsOn(data),
 		Environment:    c.indentYAMLLines(safeOutputsEnvironment, "    "),
 		Permissions:    permissions.RenderToYAML(),
 		TimeoutMinutes: 15, // Slightly longer timeout for consolidated job with multiple steps
diff --git a/pkg/workflow/compiler_types.go b/pkg/workflow/compiler_types.go
index f81bc0beee9..55fd6843379 100644
--- a/pkg/workflow/compiler_types.go
+++ b/pkg/workflow/compiler_types.go
@@ -368,6 +368,7 @@ type WorkflowData struct {
 	CustomSteps                 string
 	PostSteps                   string // steps to run after AI execution
 	RunsOn                      string
+	RunsOnActivation            string // runner override for all framework/generated jobs (activation, safe-outputs, unlock, etc.)
 	Environment                 string // environment setting for the main job
 	Container                   string // container setting for the main job
 	Services                    string // services setting for the main job
diff --git a/pkg/workflow/compiler_unlock_job.go b/pkg/workflow/compiler_unlock_job.go
index 71fa6d33698..0a4d40b861a 100644
--- a/pkg/workflow/compiler_unlock_job.go
+++ b/pkg/workflow/compiler_unlock_job.go
@@ -98,7 +98,7 @@ func (c *Compiler) buildUnlockJob(data *WorkflowData, threatDetectionEnabled boo
 		Name:           "unlock",
 		Needs:          needs,
 		If:             RenderCondition(alwaysFunc),
-		RunsOn:         c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:         c.formatFrameworkJobRunsOn(data),
 		Permissions:    permissions,
 		Steps:          steps,
 		TimeoutMinutes: 5, // Short timeout - unlock is a quick operation
diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go
index f88222d5937..c5f9c3036bd 100644
--- a/pkg/workflow/frontmatter_types.go
+++ b/pkg/workflow/frontmatter_types.go
@@ -175,14 +175,15 @@ type FrontmatterConfig struct {
 	Secrets  map[string]any    `json:"secrets,omitempty"`
 
 	// Workflow execution settings
-	RunsOn      string         `json:"runs-on,omitempty"`
-	RunName     string         `json:"run-name,omitempty"`
-	Steps       []any          `json:"steps,omitempty"`       // Custom workflow steps
-	PostSteps   []any          `json:"post-steps,omitempty"`  // Post-workflow steps
-	Environment map[string]any `json:"environment,omitempty"` // GitHub environment
-	Container   map[string]any `json:"container,omitempty"`
-	Services    map[string]any `json:"services,omitempty"`
-	Cache       map[string]any `json:"cache,omitempty"`
+	RunsOn           string         `json:"runs-on,omitempty"`
+	RunsOnActivation string         `json:"runs-on-activation,omitempty"` // Runner for all framework/generated jobs (activation, safe-outputs, unlock, etc.)
+	RunName          string         `json:"run-name,omitempty"`
+	Steps            []any          `json:"steps,omitempty"`       // Custom workflow steps
+	PostSteps        []any          `json:"post-steps,omitempty"`  // Post-workflow steps
+	Environment      map[string]any `json:"environment,omitempty"` // GitHub environment
+	Container        map[string]any `json:"container,omitempty"`
+	Services         map[string]any `json:"services,omitempty"`
+	Cache            map[string]any `json:"cache,omitempty"`
 
 	// Import and inclusion
 	Imports        any            `json:"imports,omitempty"`         // Can be string or array
@@ -634,6 +635,9 @@ func (fc *FrontmatterConfig) ToMap() map[string]any {
 	if fc.RunsOn != "" {
 		result["runs-on"] = fc.RunsOn
 	}
+	if fc.RunsOnActivation != "" {
+		result["runs-on-activation"] = fc.RunsOnActivation
+	}
 	if fc.RunName != "" {
 		result["run-name"] = fc.RunName
 	}
diff --git a/pkg/workflow/notify_comment.go b/pkg/workflow/notify_comment.go
index a50f5568596..e2907ddf583 100644
--- a/pkg/workflow/notify_comment.go
+++ b/pkg/workflow/notify_comment.go
@@ -475,7 +475,7 @@ func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, sa
 	job := &Job{
 		Name:        "conclusion",
 		If:          RenderCondition(condition),
-		RunsOn:      c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:      c.formatFrameworkJobRunsOn(data),
 		Environment: c.indentYAMLLines(resolveSafeOutputsEnvironment(data), "    "),
 		Permissions: permissions.RenderToYAML(),
 		Concurrency: concurrency,
diff --git a/pkg/workflow/safe_outputs_runs_on_test.go b/pkg/workflow/safe_outputs_runs_on_test.go
index 078d41dfcd3..c9a6a0b2d4b 100644
--- a/pkg/workflow/safe_outputs_runs_on_test.go
+++ b/pkg/workflow/safe_outputs_runs_on_test.go
@@ -238,3 +238,165 @@ This is a test workflow.`
 		t.Errorf("Unlock job does not use expected %q.\nUnlock section:\n%s", expectedRunsOn, unlockSection)
 	}
 }
+
+// TestRunsOnActivationField tests the top-level runs-on-activation field.
+func TestRunsOnActivationField(t *testing.T) {
+	tests := []struct {
+		name             string
+		frontmatter      string
+		expectedRunsOn   string
+		checkJobPatterns []string // job name patterns to check (e.g. "  activation:")
+	}{
+		{
+			name: "runs-on-activation sets runner for activation job",
+			frontmatter: `---
+on: push
+runs-on-activation: self-hosted
+---
+
+# Test Workflow
+
+This is a test workflow.`,
+			expectedRunsOn:   "runs-on: self-hosted",
+			checkJobPatterns: []string{"\n  activation:"},
+		},
+		{
+			name: "runs-on-activation without safe-outputs section",
+			frontmatter: `---
+on: push
+runs-on-activation: ubuntu-22.04
+---
+
+# Test Workflow
+
+This is a test workflow.`,
+			expectedRunsOn:   "runs-on: ubuntu-22.04",
+			checkJobPatterns: []string{"\n  activation:"},
+		},
+		{
+			name: "safe-outputs.runs-on takes precedence over runs-on-activation",
+			frontmatter: `---
+on: push
+runs-on-activation: ubuntu-22.04
+safe-outputs:
+  create-issue:
+    title-prefix: "[ai] "
+  runs-on: self-hosted
+---
+
+# Test Workflow
+
+This is a test workflow.`,
+			expectedRunsOn:   "runs-on: self-hosted",
+			checkJobPatterns: []string{"\n  activation:", "\n  safe_outputs:"},
+		},
+		{
+			name: "default used when neither runs-on-activation nor safe-outputs.runs-on is set",
+			frontmatter: `---
+on: push
+---
+
+# Test Workflow
+
+This is a test workflow.`,
+			expectedRunsOn:   "runs-on: " + constants.DefaultActivationJobRunnerImage,
+			checkJobPatterns: []string{"\n  activation:"},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			tmpDir := testutil.TempDir(t, "workflow-runs-on-activation-test")
+
+			testFile := filepath.Join(tmpDir, "test.md")
+			if err := os.WriteFile(testFile, []byte(tt.frontmatter), 0644); err != nil {
+				t.Fatal(err)
+			}
+
+			compiler := NewCompiler()
+			if err := compiler.CompileWorkflow(testFile); err != nil {
+				t.Fatalf("Failed to compile workflow: %v", err)
+			}
+
+			lockFile := filepath.Join(tmpDir, "test.lock.yml")
+			yamlContent, err := os.ReadFile(lockFile)
+			if err != nil {
+				t.Fatalf("Failed to read lock file: %v", err)
+			}
+			yamlStr := string(yamlContent)
+
+			for _, jobPattern := range tt.checkJobPatterns {
+				jobStart := strings.Index(yamlStr, jobPattern)
+				if jobStart == -1 {
+					t.Logf("Job pattern %q not found in lock file (may not be generated for this config)", jobPattern)
+					continue
+				}
+				jobSection := yamlStr[jobStart:min(jobStart+500, len(yamlStr))]
+				if !strings.Contains(jobSection, tt.expectedRunsOn) {
+					t.Errorf("Job matching %q does not use expected runs-on %q.\nJob section:\n%s", jobPattern, tt.expectedRunsOn, jobSection)
+				}
+			}
+		})
+	}
+}
+
+// TestFormatFrameworkJobRunsOn tests the formatFrameworkJobRunsOn helper directly.
+func TestFormatFrameworkJobRunsOn(t *testing.T) {
+	compiler := NewCompiler()
+
+	tests := []struct {
+		name           string
+		data           *WorkflowData
+		expectedRunsOn string
+	}{
+		{
+			name:           "nil WorkflowData returns default",
+			data:           nil,
+			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
+		},
+		{
+			name:           "empty WorkflowData returns default",
+			data:           &WorkflowData{},
+			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
+		},
+		{
+			name: "runs-on-activation used when safe-outputs.runs-on is empty",
+			data: &WorkflowData{
+				RunsOnActivation: "self-hosted",
+			},
+			expectedRunsOn: "runs-on: self-hosted",
+		},
+		{
+			name: "safe-outputs.runs-on takes precedence over runs-on-activation",
+			data: &WorkflowData{
+				RunsOnActivation: "ubuntu-22.04",
+				SafeOutputs:      &SafeOutputsConfig{RunsOn: "self-hosted"},
+			},
+			expectedRunsOn: "runs-on: self-hosted",
+		},
+		{
+			name: "safe-outputs.runs-on used when runs-on-activation is empty",
+			data: &WorkflowData{
+				SafeOutputs: &SafeOutputsConfig{RunsOn: "windows-latest"},
+			},
+			expectedRunsOn: "runs-on: windows-latest",
+		},
+		{
+			name: "default when safe-outputs present but runs-on is empty",
+			data: &WorkflowData{
+				RunsOnActivation: "",
+				SafeOutputs:      &SafeOutputsConfig{},
+			},
+			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := compiler.formatFrameworkJobRunsOn(tt.data)
+			if result != tt.expectedRunsOn {
+				t.Errorf("formatFrameworkJobRunsOn() = %q, want %q", result, tt.expectedRunsOn)
+			}
+		})
+	}
+}
diff --git a/pkg/workflow/safe_outputs_runtime.go b/pkg/workflow/safe_outputs_runtime.go
index ce07fd36f06..5e558eb184a 100644
--- a/pkg/workflow/safe_outputs_runtime.go
+++ b/pkg/workflow/safe_outputs_runtime.go
@@ -27,6 +27,26 @@ func (c *Compiler) formatSafeOutputsRunsOn(safeOutputs *SafeOutputsConfig) strin
 	return "runs-on: " + safeOutputs.RunsOn
 }
 
+// formatFrameworkJobRunsOn returns the runs-on value for framework/generated jobs
+// (activation, pre-activation, safe-outputs, unlock, APM, etc.).
+//
+// Precedence (highest to lowest):
+//  1. safe-outputs.runs-on — explicit per-section override
+//  2. runs-on-activation   — top-level field for all framework jobs
+//  3. DefaultActivationJobRunnerImage — compiled-in default
+func (c *Compiler) formatFrameworkJobRunsOn(data *WorkflowData) string {
+	if data != nil && data.SafeOutputs != nil && data.SafeOutputs.RunsOn != "" {
+		safeOutputsRuntimeLog.Printf("Framework job runs-on from safe-outputs: %s", data.SafeOutputs.RunsOn)
+		return "runs-on: " + data.SafeOutputs.RunsOn
+	}
+	if data != nil && data.RunsOnActivation != "" {
+		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-activation: %s", data.RunsOnActivation)
+		return "runs-on: " + data.RunsOnActivation
+	}
+	safeOutputsRuntimeLog.Printf("Framework job runs-on using default: %s", constants.DefaultActivationJobRunnerImage)
+	return "runs-on: " + constants.DefaultActivationJobRunnerImage
+}
+
 // usesPatchesAndCheckouts checks if the workflow uses safe outputs that require
 // git patches and checkouts (create-pull-request or push-to-pull-request-branch).
 // Staged handlers are excluded because they only emit preview output and do not

From 256a893f96894fa88d68e6fb6c7a67583fa95a01 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 30 Mar 2026 00:19:49 +0000
Subject: [PATCH 3/4] refactor: rename runs-on-activation to runs-on-slim,
 cover all framework jobs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- Rename `runs-on-activation` → `runs-on-slim` per reviewer feedback
- Extend formatFrameworkJobRunsOn coverage to all remaining framework
  jobs with previously hardcoded runners:
  - update_cache_memory (cache.go): was ubuntu-latest
  - push_repo_memory (repo_memory.go): was ubuntu-latest
  - buildSafeOutputJob (safe_outputs_jobs.go): was safe-outputs.runs-on only

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9777dcec-c84d-4257-ba9c-af7b97370526

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../agent-performance-analyzer.lock.yml       |  2 +-
 .../workflows/agent-persona-explorer.lock.yml |  2 +-
 .github/workflows/audit-workflows.lock.yml    |  4 +--
 .github/workflows/ci-coach.lock.yml           |  2 +-
 .github/workflows/ci-doctor.lock.yml          |  2 +-
 .../claude-code-user-docs-review.lock.yml     |  2 +-
 .../workflows/cli-version-checker.lock.yml    |  2 +-
 .github/workflows/cloclo.lock.yml             |  2 +-
 .../workflows/code-scanning-fixer.lock.yml    |  4 +--
 .../constraint-solving-potd.lock.yml          |  2 +-
 .../workflows/copilot-agent-analysis.lock.yml |  4 +--
 .../copilot-cli-deep-research.lock.yml        |  2 +-
 .../copilot-pr-merged-report.lock.yml         |  2 +-
 .../copilot-pr-nlp-analysis.lock.yml          |  4 +--
 .../copilot-pr-prompt-analysis.lock.yml       |  4 +--
 .../copilot-session-insights.lock.yml         |  4 +--
 .../daily-architecture-diagram.lock.yml       |  2 +-
 .../workflows/daily-cli-performance.lock.yml  |  2 +-
 .github/workflows/daily-code-metrics.lock.yml |  4 +--
 .../daily-community-attribution.lock.yml      |  2 +-
 .../workflows/daily-compiler-quality.lock.yml |  2 +-
 .../daily-copilot-token-report.lock.yml       |  4 +--
 .github/workflows/daily-doc-healer.lock.yml   |  2 +-
 .github/workflows/daily-doc-updater.lock.yml  |  2 +-
 .../workflows/daily-firewall-report.lock.yml  |  2 +-
 .../workflows/daily-function-namer.lock.yml   |  2 +-
 .../daily-integrity-analysis.lock.yml         |  2 +-
 .../workflows/daily-issues-report.lock.yml    |  2 +-
 .../daily-mcp-concurrency-analysis.lock.yml   |  2 +-
 .github/workflows/daily-news.lock.yml         |  4 +--
 .../daily-performance-summary.lock.yml        |  2 +-
 .../daily-rendering-scripts-verifier.lock.yml |  2 +-
 .../workflows/daily-repo-chronicle.lock.yml   |  2 +-
 .../daily-safe-output-optimizer.lock.yml      |  2 +-
 .../daily-testify-uber-super-expert.lock.yml  |  2 +-
 .github/workflows/dead-code-remover.lock.yml  |  2 +-
 .github/workflows/deep-report.lock.yml        |  4 +--
 .github/workflows/delight.lock.yml            |  2 +-
 .../developer-docs-consolidator.lock.yml      |  4 +--
 .../workflows/discussion-task-miner.lock.yml  |  2 +-
 .github/workflows/firewall-escape.lock.yml    |  4 +--
 .../github-mcp-structural-analysis.lock.yml   |  2 +-
 .../github-mcp-tools-report.lock.yml          |  2 +-
 .../workflows/glossary-maintainer.lock.yml    |  4 +--
 .github/workflows/go-fan.lock.yml             |  2 +-
 .github/workflows/go-logger.lock.yml          |  2 +-
 .github/workflows/gpclean.lock.yml            |  2 +-
 .github/workflows/grumpy-reviewer.lock.yml    |  2 +-
 .../workflows/instructions-janitor.lock.yml   |  2 +-
 .github/workflows/jsweep.lock.yml             |  2 +-
 .github/workflows/lockfile-stats.lock.yml     |  2 +-
 .github/workflows/mcp-inspector.lock.yml      |  2 +-
 .github/workflows/metrics-collector.lock.yml  |  2 +-
 .github/workflows/org-health-report.lock.yml  |  2 +-
 .github/workflows/pdf-summary.lock.yml        |  2 +-
 .github/workflows/poem-bot.lock.yml           |  2 +-
 .github/workflows/portfolio-analyst.lock.yml  |  2 +-
 .../workflows/pr-nitpick-reviewer.lock.yml    |  2 +-
 .github/workflows/pr-triage-agent.lock.yml    |  2 +-
 .../prompt-clustering-analysis.lock.yml       |  2 +-
 .github/workflows/python-data-charts.lock.yml |  2 +-
 .github/workflows/q.lock.yml                  |  2 +-
 .../workflows/repo-audit-analyzer.lock.yml    |  2 +-
 .../repository-quality-improver.lock.yml      |  2 +-
 .github/workflows/safe-output-health.lock.yml |  2 +-
 .../schema-consistency-checker.lock.yml       |  2 +-
 .github/workflows/scout.lock.yml              |  2 +-
 .../workflows/security-compliance.lock.yml    |  2 +-
 .github/workflows/security-review.lock.yml    |  2 +-
 .github/workflows/sergo.lock.yml              |  2 +-
 .../workflows/slide-deck-maintainer.lock.yml  |  2 +-
 .github/workflows/smoke-claude.lock.yml       |  2 +-
 .github/workflows/smoke-codex.lock.yml        |  2 +-
 .github/workflows/smoke-copilot-arm.lock.yml  |  2 +-
 .github/workflows/smoke-copilot.lock.yml      |  2 +-
 .github/workflows/smoke-gemini.lock.yml       |  2 +-
 .../smoke-update-cross-repo-pr.lock.yml       |  2 +-
 .../workflows/stale-repo-identifier.lock.yml  |  2 +-
 .../workflows/static-analysis-report.lock.yml |  2 +-
 .../workflows/step-name-alignment.lock.yml    |  2 +-
 .github/workflows/super-linter.lock.yml       |  2 +-
 .../workflows/technical-doc-writer.lock.yml   |  4 +--
 .../test-create-pr-error-handling.lock.yml    |  2 +-
 .github/workflows/unbloat-docs.lock.yml       |  2 +-
 .../weekly-blog-post-writer.lock.yml          |  2 +-
 .../workflows/weekly-issue-summary.lock.yml   |  2 +-
 .../workflow-health-manager.lock.yml          |  2 +-
 pkg/parser/schemas/main_workflow_schema.json  |  2 +-
 pkg/workflow/cache.go                         |  2 +-
 .../compiler_orchestrator_workflow.go         |  6 ++--
 pkg/workflow/compiler_types.go                |  2 +-
 pkg/workflow/frontmatter_types.go             | 22 ++++++------
 pkg/workflow/repo_memory.go                   |  2 +-
 pkg/workflow/safe_outputs_jobs.go             |  2 +-
 pkg/workflow/safe_outputs_runs_on_test.go     | 36 +++++++++----------
 pkg/workflow/safe_outputs_runtime.go          |  8 ++---
 96 files changed, 142 insertions(+), 142 deletions(-)

diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml
index 8ce2e9fdb61..6a4a5ccd99e 100644
--- a/.github/workflows/agent-performance-analyzer.lock.yml
+++ b/.github/workflows/agent-performance-analyzer.lock.yml
@@ -1219,7 +1219,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/agent-persona-explorer.lock.yml b/.github/workflows/agent-persona-explorer.lock.yml
index 69c62b49268..185c42b5f7a 100644
--- a/.github/workflows/agent-persona-explorer.lock.yml
+++ b/.github/workflows/agent-persona-explorer.lock.yml
@@ -1249,7 +1249,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml
index b052f9939d0..a3e901aebcd 100644
--- a/.github/workflows/audit-workflows.lock.yml
+++ b/.github/workflows/audit-workflows.lock.yml
@@ -1298,7 +1298,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1465,7 +1465,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml
index 1333ad6820b..1d45fd653e2 100644
--- a/.github/workflows/ci-coach.lock.yml
+++ b/.github/workflows/ci-coach.lock.yml
@@ -1252,7 +1252,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml
index 3edcb82beed..942e428ca59 100644
--- a/.github/workflows/ci-doctor.lock.yml
+++ b/.github/workflows/ci-doctor.lock.yml
@@ -1405,7 +1405,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/claude-code-user-docs-review.lock.yml b/.github/workflows/claude-code-user-docs-review.lock.yml
index 63c7517826c..fb0e24b759e 100644
--- a/.github/workflows/claude-code-user-docs-review.lock.yml
+++ b/.github/workflows/claude-code-user-docs-review.lock.yml
@@ -1211,7 +1211,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml
index 6cf14f6b258..9b00d304b9a 100644
--- a/.github/workflows/cli-version-checker.lock.yml
+++ b/.github/workflows/cli-version-checker.lock.yml
@@ -1216,7 +1216,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml
index 176999bb603..ae710072a79 100644
--- a/.github/workflows/cloclo.lock.yml
+++ b/.github/workflows/cloclo.lock.yml
@@ -1672,7 +1672,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml
index 5a537927cb8..6369bdc1553 100644
--- a/.github/workflows/code-scanning-fixer.lock.yml
+++ b/.github/workflows/code-scanning-fixer.lock.yml
@@ -1169,7 +1169,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1367,7 +1367,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/constraint-solving-potd.lock.yml b/.github/workflows/constraint-solving-potd.lock.yml
index cb0405f152f..d54da22f9b8 100644
--- a/.github/workflows/constraint-solving-potd.lock.yml
+++ b/.github/workflows/constraint-solving-potd.lock.yml
@@ -1112,7 +1112,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml
index 16c85ac0267..c29c977347b 100644
--- a/.github/workflows/copilot-agent-analysis.lock.yml
+++ b/.github/workflows/copilot-agent-analysis.lock.yml
@@ -1181,7 +1181,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1347,7 +1347,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml
index 0a67f69a325..a2bf1b751a3 100644
--- a/.github/workflows/copilot-cli-deep-research.lock.yml
+++ b/.github/workflows/copilot-cli-deep-research.lock.yml
@@ -1079,7 +1079,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml
index 0a008c2e5dc..f621b30487c 100644
--- a/.github/workflows/copilot-pr-merged-report.lock.yml
+++ b/.github/workflows/copilot-pr-merged-report.lock.yml
@@ -1291,7 +1291,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml
index 8e8f66900ec..58c460b238c 100644
--- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml
+++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml
@@ -1176,7 +1176,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1342,7 +1342,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml
index 7843c85cbf7..5acdef232f5 100644
--- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml
+++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml
@@ -1112,7 +1112,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1278,7 +1278,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml
index b21b5479dbd..40fd0731cc5 100644
--- a/.github/workflows/copilot-session-insights.lock.yml
+++ b/.github/workflows/copilot-session-insights.lock.yml
@@ -1244,7 +1244,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1410,7 +1410,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-architecture-diagram.lock.yml b/.github/workflows/daily-architecture-diagram.lock.yml
index 206533355b2..a258174e7ac 100644
--- a/.github/workflows/daily-architecture-diagram.lock.yml
+++ b/.github/workflows/daily-architecture-diagram.lock.yml
@@ -1226,7 +1226,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml
index d2cb761e3c1..11a4d75cf17 100644
--- a/.github/workflows/daily-cli-performance.lock.yml
+++ b/.github/workflows/daily-cli-performance.lock.yml
@@ -1325,7 +1325,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml
index f72a397dd83..c111f4e4948 100644
--- a/.github/workflows/daily-code-metrics.lock.yml
+++ b/.github/workflows/daily-code-metrics.lock.yml
@@ -1219,7 +1219,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1386,7 +1386,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-community-attribution.lock.yml b/.github/workflows/daily-community-attribution.lock.yml
index 72556476950..c58f7917e54 100644
--- a/.github/workflows/daily-community-attribution.lock.yml
+++ b/.github/workflows/daily-community-attribution.lock.yml
@@ -1125,7 +1125,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/daily-compiler-quality.lock.yml b/.github/workflows/daily-compiler-quality.lock.yml
index 38a9746398e..b087cb6d128 100644
--- a/.github/workflows/daily-compiler-quality.lock.yml
+++ b/.github/workflows/daily-compiler-quality.lock.yml
@@ -1226,7 +1226,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml
index 7a3f19c2444..83feb3e484e 100644
--- a/.github/workflows/daily-copilot-token-report.lock.yml
+++ b/.github/workflows/daily-copilot-token-report.lock.yml
@@ -1181,7 +1181,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1348,7 +1348,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-doc-healer.lock.yml b/.github/workflows/daily-doc-healer.lock.yml
index 8d4a367bd26..b09270b8aca 100644
--- a/.github/workflows/daily-doc-healer.lock.yml
+++ b/.github/workflows/daily-doc-healer.lock.yml
@@ -1495,7 +1495,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml
index 1a001a99659..c1d01c5ee78 100644
--- a/.github/workflows/daily-doc-updater.lock.yml
+++ b/.github/workflows/daily-doc-updater.lock.yml
@@ -1437,7 +1437,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml
index 12f0ad45496..ef914757b15 100644
--- a/.github/workflows/daily-firewall-report.lock.yml
+++ b/.github/workflows/daily-firewall-report.lock.yml
@@ -1274,7 +1274,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-function-namer.lock.yml b/.github/workflows/daily-function-namer.lock.yml
index c4afe171c8b..b699da556fc 100644
--- a/.github/workflows/daily-function-namer.lock.yml
+++ b/.github/workflows/daily-function-namer.lock.yml
@@ -1278,7 +1278,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-integrity-analysis.lock.yml b/.github/workflows/daily-integrity-analysis.lock.yml
index dfd1fd7aeeb..d0d2cd47935 100644
--- a/.github/workflows/daily-integrity-analysis.lock.yml
+++ b/.github/workflows/daily-integrity-analysis.lock.yml
@@ -1279,7 +1279,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml
index ee4eb2ec215..1ea617aa021 100644
--- a/.github/workflows/daily-issues-report.lock.yml
+++ b/.github/workflows/daily-issues-report.lock.yml
@@ -1292,7 +1292,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml
index 2d99274243e..22bc60558be 100644
--- a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml
+++ b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml
@@ -1261,7 +1261,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml
index cfbc20bfabf..2f2a69c9a6d 100644
--- a/.github/workflows/daily-news.lock.yml
+++ b/.github/workflows/daily-news.lock.yml
@@ -1252,7 +1252,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1419,7 +1419,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml
index 9c8315ac555..3ecbb9b640f 100644
--- a/.github/workflows/daily-performance-summary.lock.yml
+++ b/.github/workflows/daily-performance-summary.lock.yml
@@ -1716,7 +1716,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-rendering-scripts-verifier.lock.yml b/.github/workflows/daily-rendering-scripts-verifier.lock.yml
index ec6abe441da..0a1cb11716e 100644
--- a/.github/workflows/daily-rendering-scripts-verifier.lock.yml
+++ b/.github/workflows/daily-rendering-scripts-verifier.lock.yml
@@ -1427,7 +1427,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml
index 7ff4b022fe9..a705bf0e149 100644
--- a/.github/workflows/daily-repo-chronicle.lock.yml
+++ b/.github/workflows/daily-repo-chronicle.lock.yml
@@ -1196,7 +1196,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-safe-output-optimizer.lock.yml b/.github/workflows/daily-safe-output-optimizer.lock.yml
index 8fc90081be6..9da26329bdc 100644
--- a/.github/workflows/daily-safe-output-optimizer.lock.yml
+++ b/.github/workflows/daily-safe-output-optimizer.lock.yml
@@ -1366,7 +1366,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml
index 0b96052c6ba..20195335bf6 100644
--- a/.github/workflows/daily-testify-uber-super-expert.lock.yml
+++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml
@@ -1208,7 +1208,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/dead-code-remover.lock.yml b/.github/workflows/dead-code-remover.lock.yml
index 54a2cf94a9a..a914c010d70 100644
--- a/.github/workflows/dead-code-remover.lock.yml
+++ b/.github/workflows/dead-code-remover.lock.yml
@@ -1256,7 +1256,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml
index 4cd12565ac4..ca03bed4aad 100644
--- a/.github/workflows/deep-report.lock.yml
+++ b/.github/workflows/deep-report.lock.yml
@@ -1280,7 +1280,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1449,7 +1449,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml
index cf81c8f20fb..1408bd474b8 100644
--- a/.github/workflows/delight.lock.yml
+++ b/.github/workflows/delight.lock.yml
@@ -1124,7 +1124,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml
index 91cc4aade9f..332b9a48535 100644
--- a/.github/workflows/developer-docs-consolidator.lock.yml
+++ b/.github/workflows/developer-docs-consolidator.lock.yml
@@ -1449,7 +1449,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1648,7 +1648,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml
index cf28d21f938..916c47856b5 100644
--- a/.github/workflows/discussion-task-miner.lock.yml
+++ b/.github/workflows/discussion-task-miner.lock.yml
@@ -1107,7 +1107,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml
index 067c12788f0..c2fa435c42f 100644
--- a/.github/workflows/firewall-escape.lock.yml
+++ b/.github/workflows/firewall-escape.lock.yml
@@ -1182,7 +1182,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1348,7 +1348,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml
index 64f6e00c186..c91f55a801b 100644
--- a/.github/workflows/github-mcp-structural-analysis.lock.yml
+++ b/.github/workflows/github-mcp-structural-analysis.lock.yml
@@ -1260,7 +1260,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml
index 30b19714a52..e98b7f953b0 100644
--- a/.github/workflows/github-mcp-tools-report.lock.yml
+++ b/.github/workflows/github-mcp-tools-report.lock.yml
@@ -1295,7 +1295,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml
index 9a3d5c6c55e..4a867b29f82 100644
--- a/.github/workflows/glossary-maintainer.lock.yml
+++ b/.github/workflows/glossary-maintainer.lock.yml
@@ -1344,7 +1344,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1542,7 +1542,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml
index d24c09ba908..df7936196d4 100644
--- a/.github/workflows/go-fan.lock.yml
+++ b/.github/workflows/go-fan.lock.yml
@@ -1291,7 +1291,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml
index b5c78721889..e2f709c6f9e 100644
--- a/.github/workflows/go-logger.lock.yml
+++ b/.github/workflows/go-logger.lock.yml
@@ -1455,7 +1455,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/gpclean.lock.yml b/.github/workflows/gpclean.lock.yml
index 471a875bcb7..2e0ade53bb8 100644
--- a/.github/workflows/gpclean.lock.yml
+++ b/.github/workflows/gpclean.lock.yml
@@ -1148,7 +1148,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml
index 566a874ebfc..430be2c8c46 100644
--- a/.github/workflows/grumpy-reviewer.lock.yml
+++ b/.github/workflows/grumpy-reviewer.lock.yml
@@ -1287,7 +1287,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml
index 71959bd84a2..9ab0ee945e2 100644
--- a/.github/workflows/instructions-janitor.lock.yml
+++ b/.github/workflows/instructions-janitor.lock.yml
@@ -1276,7 +1276,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml
index e0a09db0741..b974b33961b 100644
--- a/.github/workflows/jsweep.lock.yml
+++ b/.github/workflows/jsweep.lock.yml
@@ -1273,7 +1273,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml
index 1c876abcb53..493d44c8df6 100644
--- a/.github/workflows/lockfile-stats.lock.yml
+++ b/.github/workflows/lockfile-stats.lock.yml
@@ -1202,7 +1202,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml
index 8b2ab211bc3..d78bde9b3eb 100644
--- a/.github/workflows/mcp-inspector.lock.yml
+++ b/.github/workflows/mcp-inspector.lock.yml
@@ -1960,7 +1960,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/metrics-collector.lock.yml b/.github/workflows/metrics-collector.lock.yml
index 06ac3960bc9..373a446e53c 100644
--- a/.github/workflows/metrics-collector.lock.yml
+++ b/.github/workflows/metrics-collector.lock.yml
@@ -681,7 +681,7 @@ jobs:
   push_repo_memory:
     needs: agent
     if: always()
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml
index ec57b834f20..79aabe10efa 100644
--- a/.github/workflows/org-health-report.lock.yml
+++ b/.github/workflows/org-health-report.lock.yml
@@ -1195,7 +1195,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml
index 318911d9bd0..b2dc680aabd 100644
--- a/.github/workflows/pdf-summary.lock.yml
+++ b/.github/workflows/pdf-summary.lock.yml
@@ -1326,7 +1326,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml
index f417d74ff2f..ab84f4936cc 100644
--- a/.github/workflows/poem-bot.lock.yml
+++ b/.github/workflows/poem-bot.lock.yml
@@ -1638,7 +1638,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml
index 46b316f0cf7..5fcaf05e316 100644
--- a/.github/workflows/portfolio-analyst.lock.yml
+++ b/.github/workflows/portfolio-analyst.lock.yml
@@ -1285,7 +1285,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml
index 2cb7e41980c..6d56e2ec397 100644
--- a/.github/workflows/pr-nitpick-reviewer.lock.yml
+++ b/.github/workflows/pr-nitpick-reviewer.lock.yml
@@ -1323,7 +1323,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml
index ceab9e306a9..5ceb4ea8f6e 100644
--- a/.github/workflows/pr-triage-agent.lock.yml
+++ b/.github/workflows/pr-triage-agent.lock.yml
@@ -1093,7 +1093,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml
index 6532dfa262d..6e6713a531e 100644
--- a/.github/workflows/prompt-clustering-analysis.lock.yml
+++ b/.github/workflows/prompt-clustering-analysis.lock.yml
@@ -1347,7 +1347,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml
index 670af2b6e98..79e31c396ee 100644
--- a/.github/workflows/python-data-charts.lock.yml
+++ b/.github/workflows/python-data-charts.lock.yml
@@ -1268,7 +1268,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml
index 7bff9f98775..75a1c351785 100644
--- a/.github/workflows/q.lock.yml
+++ b/.github/workflows/q.lock.yml
@@ -1527,7 +1527,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/repo-audit-analyzer.lock.yml b/.github/workflows/repo-audit-analyzer.lock.yml
index 6dd1a0be4a1..541c7d04990 100644
--- a/.github/workflows/repo-audit-analyzer.lock.yml
+++ b/.github/workflows/repo-audit-analyzer.lock.yml
@@ -1144,7 +1144,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml
index b9a70343202..6aecbb868d0 100644
--- a/.github/workflows/repository-quality-improver.lock.yml
+++ b/.github/workflows/repository-quality-improver.lock.yml
@@ -1206,7 +1206,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml
index c26e65c3f13..4c3799ce862 100644
--- a/.github/workflows/safe-output-health.lock.yml
+++ b/.github/workflows/safe-output-health.lock.yml
@@ -1307,7 +1307,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml
index 4e2396b0216..b3ca73f6433 100644
--- a/.github/workflows/schema-consistency-checker.lock.yml
+++ b/.github/workflows/schema-consistency-checker.lock.yml
@@ -1202,7 +1202,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml
index 926cd4c4275..9b8d4092037 100644
--- a/.github/workflows/scout.lock.yml
+++ b/.github/workflows/scout.lock.yml
@@ -1515,7 +1515,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml
index 18bb482e28e..435da33ac8e 100644
--- a/.github/workflows/security-compliance.lock.yml
+++ b/.github/workflows/security-compliance.lock.yml
@@ -1072,7 +1072,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml
index 86facdb3626..4762a9cc719 100644
--- a/.github/workflows/security-review.lock.yml
+++ b/.github/workflows/security-review.lock.yml
@@ -1363,7 +1363,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/sergo.lock.yml b/.github/workflows/sergo.lock.yml
index f1c824e105e..c7e3b0e7384 100644
--- a/.github/workflows/sergo.lock.yml
+++ b/.github/workflows/sergo.lock.yml
@@ -1291,7 +1291,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/slide-deck-maintainer.lock.yml b/.github/workflows/slide-deck-maintainer.lock.yml
index ac17aec4f6b..c2a2a1a5b94 100644
--- a/.github/workflows/slide-deck-maintainer.lock.yml
+++ b/.github/workflows/slide-deck-maintainer.lock.yml
@@ -1332,7 +1332,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml
index 4e0070840ab..2c429716709 100644
--- a/.github/workflows/smoke-claude.lock.yml
+++ b/.github/workflows/smoke-claude.lock.yml
@@ -2790,7 +2790,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index 24cfc051efa..6e321c96214 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -1860,7 +1860,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml
index b8efd704e47..b7e1aebe36f 100644
--- a/.github/workflows/smoke-copilot-arm.lock.yml
+++ b/.github/workflows/smoke-copilot-arm.lock.yml
@@ -2190,7 +2190,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml
index c9dd1595d80..cbf310f2658 100644
--- a/.github/workflows/smoke-copilot.lock.yml
+++ b/.github/workflows/smoke-copilot.lock.yml
@@ -2236,7 +2236,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/smoke-gemini.lock.yml b/.github/workflows/smoke-gemini.lock.yml
index 001bc4fb670..148d922291f 100644
--- a/.github/workflows/smoke-gemini.lock.yml
+++ b/.github/workflows/smoke-gemini.lock.yml
@@ -1441,7 +1441,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/smoke-update-cross-repo-pr.lock.yml b/.github/workflows/smoke-update-cross-repo-pr.lock.yml
index eeee9cdf135..5934ddef033 100644
--- a/.github/workflows/smoke-update-cross-repo-pr.lock.yml
+++ b/.github/workflows/smoke-update-cross-repo-pr.lock.yml
@@ -1330,7 +1330,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml
index 5c1f1f57cc2..db40a331bff 100644
--- a/.github/workflows/stale-repo-identifier.lock.yml
+++ b/.github/workflows/stale-repo-identifier.lock.yml
@@ -1252,7 +1252,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml
index 65f12de8bb8..6815f2e4b67 100644
--- a/.github/workflows/static-analysis-report.lock.yml
+++ b/.github/workflows/static-analysis-report.lock.yml
@@ -1285,7 +1285,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/step-name-alignment.lock.yml b/.github/workflows/step-name-alignment.lock.yml
index 7602ca14f70..2826269742c 100644
--- a/.github/workflows/step-name-alignment.lock.yml
+++ b/.github/workflows/step-name-alignment.lock.yml
@@ -1216,7 +1216,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml
index 628d54cc01c..82aeec3f35b 100644
--- a/.github/workflows/super-linter.lock.yml
+++ b/.github/workflows/super-linter.lock.yml
@@ -1212,7 +1212,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml
index 2404d471100..c8c116eafa0 100644
--- a/.github/workflows/technical-doc-writer.lock.yml
+++ b/.github/workflows/technical-doc-writer.lock.yml
@@ -1348,7 +1348,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
@@ -1550,7 +1550,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/test-create-pr-error-handling.lock.yml b/.github/workflows/test-create-pr-error-handling.lock.yml
index 3e9c29a81a3..1e1f99c401d 100644
--- a/.github/workflows/test-create-pr-error-handling.lock.yml
+++ b/.github/workflows/test-create-pr-error-handling.lock.yml
@@ -1248,7 +1248,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml
index a4504f0b3f3..8d9ccd76258 100644
--- a/.github/workflows/unbloat-docs.lock.yml
+++ b/.github/workflows/unbloat-docs.lock.yml
@@ -1685,7 +1685,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/weekly-blog-post-writer.lock.yml b/.github/workflows/weekly-blog-post-writer.lock.yml
index 3d41d62bf1d..8f8c35c3785 100644
--- a/.github/workflows/weekly-blog-post-writer.lock.yml
+++ b/.github/workflows/weekly-blog-post-writer.lock.yml
@@ -1310,7 +1310,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml
index f5af202b3d3..27ff36e44ec 100644
--- a/.github/workflows/weekly-issue-summary.lock.yml
+++ b/.github/workflows/weekly-issue-summary.lock.yml
@@ -1179,7 +1179,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: read
     env:
diff --git a/.github/workflows/workflow-health-manager.lock.yml b/.github/workflows/workflow-health-manager.lock.yml
index f3cc3cf7079..9285be22ea4 100644
--- a/.github/workflows/workflow-health-manager.lock.yml
+++ b/.github/workflows/workflow-health-manager.lock.yml
@@ -1174,7 +1174,7 @@ jobs:
       - agent
       - detection
     if: always() && (needs.detection.result == 'success' || needs.detection.result == 'skipped')
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-slim
     permissions:
       contents: write
     concurrency:
diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json
index 706140a3b20..36c881ac942 100644
--- a/pkg/parser/schemas/main_workflow_schema.json
+++ b/pkg/parser/schemas/main_workflow_schema.json
@@ -2631,7 +2631,7 @@
         }
       ]
     },
-    "runs-on-activation": {
+    "runs-on-slim": {
       "type": "string",
       "description": "Runner for all framework/generated jobs (activation, pre-activation, safe-outputs, unlock, APM, etc.). Provides a compile-stable override for generated job runners without requiring a safe-outputs section. Overridden by safe-outputs.runs-on when both are set. Defaults to 'ubuntu-slim'. Use this when your infrastructure does not provide the default runner or when you need consistent runner selection across all jobs.",
       "examples": ["self-hosted", "ubuntu-latest", "ubuntu-22.04"]
diff --git a/pkg/workflow/cache.go b/pkg/workflow/cache.go
index 39c86f1f25e..995ad387f36 100644
--- a/pkg/workflow/cache.go
+++ b/pkg/workflow/cache.go
@@ -954,7 +954,7 @@ func (c *Compiler) buildUpdateCacheMemoryJob(data *WorkflowData, threatDetection
 	job := &Job{
 		Name:        "update_cache_memory",
 		DisplayName: "", // No display name - job ID is sufficient
-		RunsOn:      "runs-on: ubuntu-latest",
+		RunsOn:      c.formatFrameworkJobRunsOn(data),
 		If:          jobCondition,
 		Permissions: permissions,
 		Needs:       []string{string(constants.AgentJobName), string(constants.DetectionJobName)},
diff --git a/pkg/workflow/compiler_orchestrator_workflow.go b/pkg/workflow/compiler_orchestrator_workflow.go
index 39f71c036a6..9d2f6a62f63 100644
--- a/pkg/workflow/compiler_orchestrator_workflow.go
+++ b/pkg/workflow/compiler_orchestrator_workflow.go
@@ -253,10 +253,10 @@ func (c *Compiler) extractYAMLSections(frontmatter map[string]any, workflowData
 	workflowData.TimeoutMinutes = c.extractTopLevelYAMLSection(frontmatter, "timeout-minutes")
 
 	workflowData.RunsOn = c.extractTopLevelYAMLSection(frontmatter, "runs-on")
-	// Extract runs-on-activation as a plain string (no YAML formatting needed)
-	if v, ok := frontmatter["runs-on-activation"]; ok {
+	// Extract runs-on-slim as a plain string (no YAML formatting needed)
+	if v, ok := frontmatter["runs-on-slim"]; ok {
 		if s, ok := v.(string); ok {
-			workflowData.RunsOnActivation = s
+			workflowData.RunsOnSlim = s
 		}
 	}
 	workflowData.Environment = c.extractTopLevelYAMLSection(frontmatter, "environment")
diff --git a/pkg/workflow/compiler_types.go b/pkg/workflow/compiler_types.go
index 55fd6843379..3cdb27dde04 100644
--- a/pkg/workflow/compiler_types.go
+++ b/pkg/workflow/compiler_types.go
@@ -368,7 +368,7 @@ type WorkflowData struct {
 	CustomSteps                 string
 	PostSteps                   string // steps to run after AI execution
 	RunsOn                      string
-	RunsOnActivation            string // runner override for all framework/generated jobs (activation, safe-outputs, unlock, etc.)
+	RunsOnSlim                  string // runner override for all framework/generated jobs (activation, safe-outputs, unlock, etc.)
 	Environment                 string // environment setting for the main job
 	Container                   string // container setting for the main job
 	Services                    string // services setting for the main job
diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go
index c5f9c3036bd..37a1147e115 100644
--- a/pkg/workflow/frontmatter_types.go
+++ b/pkg/workflow/frontmatter_types.go
@@ -175,15 +175,15 @@ type FrontmatterConfig struct {
 	Secrets  map[string]any    `json:"secrets,omitempty"`
 
 	// Workflow execution settings
-	RunsOn           string         `json:"runs-on,omitempty"`
-	RunsOnActivation string         `json:"runs-on-activation,omitempty"` // Runner for all framework/generated jobs (activation, safe-outputs, unlock, etc.)
-	RunName          string         `json:"run-name,omitempty"`
-	Steps            []any          `json:"steps,omitempty"`       // Custom workflow steps
-	PostSteps        []any          `json:"post-steps,omitempty"`  // Post-workflow steps
-	Environment      map[string]any `json:"environment,omitempty"` // GitHub environment
-	Container        map[string]any `json:"container,omitempty"`
-	Services         map[string]any `json:"services,omitempty"`
-	Cache            map[string]any `json:"cache,omitempty"`
+	RunsOn      string         `json:"runs-on,omitempty"`
+	RunsOnSlim  string         `json:"runs-on-slim,omitempty"` // Runner for all framework/generated jobs (activation, safe-outputs, unlock, etc.)
+	RunName     string         `json:"run-name,omitempty"`
+	Steps       []any          `json:"steps,omitempty"`       // Custom workflow steps
+	PostSteps   []any          `json:"post-steps,omitempty"`  // Post-workflow steps
+	Environment map[string]any `json:"environment,omitempty"` // GitHub environment
+	Container   map[string]any `json:"container,omitempty"`
+	Services    map[string]any `json:"services,omitempty"`
+	Cache       map[string]any `json:"cache,omitempty"`
 
 	// Import and inclusion
 	Imports        any            `json:"imports,omitempty"`         // Can be string or array
@@ -635,8 +635,8 @@ func (fc *FrontmatterConfig) ToMap() map[string]any {
 	if fc.RunsOn != "" {
 		result["runs-on"] = fc.RunsOn
 	}
-	if fc.RunsOnActivation != "" {
-		result["runs-on-activation"] = fc.RunsOnActivation
+	if fc.RunsOnSlim != "" {
+		result["runs-on-slim"] = fc.RunsOnSlim
 	}
 	if fc.RunName != "" {
 		result["run-name"] = fc.RunName
diff --git a/pkg/workflow/repo_memory.go b/pkg/workflow/repo_memory.go
index 29bd7d78ec2..09998ee8287 100644
--- a/pkg/workflow/repo_memory.go
+++ b/pkg/workflow/repo_memory.go
@@ -736,7 +736,7 @@ func (c *Compiler) buildPushRepoMemoryJob(data *WorkflowData, threatDetectionEna
 	job := &Job{
 		Name:        "push_repo_memory",
 		DisplayName: "", // No display name - job ID is sufficient
-		RunsOn:      "runs-on: ubuntu-latest",
+		RunsOn:      c.formatFrameworkJobRunsOn(data),
 		If:          jobCondition,
 		Permissions: "permissions:\n      contents: write",
 		Concurrency: concurrency,
diff --git a/pkg/workflow/safe_outputs_jobs.go b/pkg/workflow/safe_outputs_jobs.go
index 6097e6622b5..8b9b52e317a 100644
--- a/pkg/workflow/safe_outputs_jobs.go
+++ b/pkg/workflow/safe_outputs_jobs.go
@@ -140,7 +140,7 @@ func (c *Compiler) buildSafeOutputJob(data *WorkflowData, config SafeOutputJobCo
 	job := &Job{
 		Name:           config.JobName,
 		If:             RenderCondition(jobCondition),
-		RunsOn:         c.formatSafeOutputsRunsOn(data.SafeOutputs),
+		RunsOn:         c.formatFrameworkJobRunsOn(data),
 		Environment:    c.indentYAMLLines(resolveSafeOutputsEnvironment(data), "    "),
 		Permissions:    config.Permissions.RenderToYAML(),
 		TimeoutMinutes: 10, // 10-minute timeout as required for all safe output jobs
diff --git a/pkg/workflow/safe_outputs_runs_on_test.go b/pkg/workflow/safe_outputs_runs_on_test.go
index c9a6a0b2d4b..0f41a023c6f 100644
--- a/pkg/workflow/safe_outputs_runs_on_test.go
+++ b/pkg/workflow/safe_outputs_runs_on_test.go
@@ -239,8 +239,8 @@ This is a test workflow.`
 	}
 }
 
-// TestRunsOnActivationField tests the top-level runs-on-activation field.
-func TestRunsOnActivationField(t *testing.T) {
+// TestRunsOnSlimField tests the top-level runs-on-slim field.
+func TestRunsOnSlimField(t *testing.T) {
 	tests := []struct {
 		name             string
 		frontmatter      string
@@ -248,10 +248,10 @@ func TestRunsOnActivationField(t *testing.T) {
 		checkJobPatterns []string // job name patterns to check (e.g. "  activation:")
 	}{
 		{
-			name: "runs-on-activation sets runner for activation job",
+			name: "runs-on-slim sets runner for activation job",
 			frontmatter: `---
 on: push
-runs-on-activation: self-hosted
+runs-on-slim: self-hosted
 ---
 
 # Test Workflow
@@ -261,10 +261,10 @@ This is a test workflow.`,
 			checkJobPatterns: []string{"\n  activation:"},
 		},
 		{
-			name: "runs-on-activation without safe-outputs section",
+			name: "runs-on-slim without safe-outputs section",
 			frontmatter: `---
 on: push
-runs-on-activation: ubuntu-22.04
+runs-on-slim: ubuntu-22.04
 ---
 
 # Test Workflow
@@ -274,10 +274,10 @@ This is a test workflow.`,
 			checkJobPatterns: []string{"\n  activation:"},
 		},
 		{
-			name: "safe-outputs.runs-on takes precedence over runs-on-activation",
+			name: "safe-outputs.runs-on takes precedence over runs-on-slim",
 			frontmatter: `---
 on: push
-runs-on-activation: ubuntu-22.04
+runs-on-slim: ubuntu-22.04
 safe-outputs:
   create-issue:
     title-prefix: "[ai] "
@@ -291,7 +291,7 @@ This is a test workflow.`,
 			checkJobPatterns: []string{"\n  activation:", "\n  safe_outputs:"},
 		},
 		{
-			name: "default used when neither runs-on-activation nor safe-outputs.runs-on is set",
+			name: "default used when neither runs-on-slim nor safe-outputs.runs-on is set",
 			frontmatter: `---
 on: push
 ---
@@ -306,7 +306,7 @@ This is a test workflow.`,
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			tmpDir := testutil.TempDir(t, "workflow-runs-on-activation-test")
+			tmpDir := testutil.TempDir(t, "workflow-runs-on-slim-test")
 
 			testFile := filepath.Join(tmpDir, "test.md")
 			if err := os.WriteFile(testFile, []byte(tt.frontmatter), 0644); err != nil {
@@ -360,22 +360,22 @@ func TestFormatFrameworkJobRunsOn(t *testing.T) {
 			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
 		},
 		{
-			name: "runs-on-activation used when safe-outputs.runs-on is empty",
+			name: "runs-on-slim used when safe-outputs.runs-on is empty",
 			data: &WorkflowData{
-				RunsOnActivation: "self-hosted",
+				RunsOnSlim: "self-hosted",
 			},
 			expectedRunsOn: "runs-on: self-hosted",
 		},
 		{
-			name: "safe-outputs.runs-on takes precedence over runs-on-activation",
+			name: "safe-outputs.runs-on takes precedence over runs-on-slim",
 			data: &WorkflowData{
-				RunsOnActivation: "ubuntu-22.04",
-				SafeOutputs:      &SafeOutputsConfig{RunsOn: "self-hosted"},
+				RunsOnSlim:  "ubuntu-22.04",
+				SafeOutputs: &SafeOutputsConfig{RunsOn: "self-hosted"},
 			},
 			expectedRunsOn: "runs-on: self-hosted",
 		},
 		{
-			name: "safe-outputs.runs-on used when runs-on-activation is empty",
+			name: "safe-outputs.runs-on used when runs-on-slim is empty",
 			data: &WorkflowData{
 				SafeOutputs: &SafeOutputsConfig{RunsOn: "windows-latest"},
 			},
@@ -384,8 +384,8 @@ func TestFormatFrameworkJobRunsOn(t *testing.T) {
 		{
 			name: "default when safe-outputs present but runs-on is empty",
 			data: &WorkflowData{
-				RunsOnActivation: "",
-				SafeOutputs:      &SafeOutputsConfig{},
+				RunsOnSlim:  "",
+				SafeOutputs: &SafeOutputsConfig{},
 			},
 			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
 		},
diff --git a/pkg/workflow/safe_outputs_runtime.go b/pkg/workflow/safe_outputs_runtime.go
index 5e558eb184a..1880d7043dc 100644
--- a/pkg/workflow/safe_outputs_runtime.go
+++ b/pkg/workflow/safe_outputs_runtime.go
@@ -32,16 +32,16 @@ func (c *Compiler) formatSafeOutputsRunsOn(safeOutputs *SafeOutputsConfig) strin
 //
 // Precedence (highest to lowest):
 //  1. safe-outputs.runs-on — explicit per-section override
-//  2. runs-on-activation   — top-level field for all framework jobs
+//  2. runs-on-slim   — top-level field for all framework jobs
 //  3. DefaultActivationJobRunnerImage — compiled-in default
 func (c *Compiler) formatFrameworkJobRunsOn(data *WorkflowData) string {
 	if data != nil && data.SafeOutputs != nil && data.SafeOutputs.RunsOn != "" {
 		safeOutputsRuntimeLog.Printf("Framework job runs-on from safe-outputs: %s", data.SafeOutputs.RunsOn)
 		return "runs-on: " + data.SafeOutputs.RunsOn
 	}
-	if data != nil && data.RunsOnActivation != "" {
-		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-activation: %s", data.RunsOnActivation)
-		return "runs-on: " + data.RunsOnActivation
+	if data != nil && data.RunsOnSlim != "" {
+		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-slim: %s", data.RunsOnSlim)
+		return "runs-on: " + data.RunsOnSlim
 	}
 	safeOutputsRuntimeLog.Printf("Framework job runs-on using default: %s", constants.DefaultActivationJobRunnerImage)
 	return "runs-on: " + constants.DefaultActivationJobRunnerImage

From 0b44aa5b86b35415cf5a2b542822d21a1c562ada Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 30 Mar 2026 00:53:19 +0000
Subject: [PATCH 4/4] docs: document runs-on-slim frontmatter field

Add documentation for the new `runs-on-slim` top-level frontmatter field
that controls the runner for all framework/generated jobs (activation,
safe-outputs, unlock, APM, etc.).

- self-hosted-runners.md: add 'Configuring the framework job runner' section
- frontmatter.md: rename Run Configuration heading to include runs-on-slim,
  add field to example and explanation
- safe-outputs.md: expand Custom Runner Image section with code example
  and cross-reference to runs-on-slim

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../docs/guides/self-hosted-runners.md        | 19 ++++++++++++++++++-
 .../src/content/docs/reference/frontmatter.md |  5 ++++-
 .../content/docs/reference/safe-outputs.md    | 12 +++++++++++-
 3 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/docs/src/content/docs/guides/self-hosted-runners.md b/docs/src/content/docs/guides/self-hosted-runners.md
index c2a33793102..e6d11c62226 100644
--- a/docs/src/content/docs/guides/self-hosted-runners.md
+++ b/docs/src/content/docs/guides/self-hosted-runners.md
@@ -90,9 +90,26 @@ safe-outputs:
 
 This is useful when your self-hosted runner lacks outbound internet access for AI detection, or when you want to run the detection job on a cheaper runner.
 
+## Configuring the framework job runner
+
+Framework jobs — activation, pre-activation, safe-outputs, unlock, APM, update_cache_memory, and push_repo_memory — default to `ubuntu-slim`. Use `runs-on-slim:` to override all of them at once:
+
+```aw
+---
+on: issues
+runs-on: [self-hosted, linux, x64]
+runs-on-slim: self-hosted
+safe-outputs:
+  create-issue: {}
+---
+```
+
+> [!NOTE]
+> `runs-on` controls only the main agent job. `runs-on-slim` controls all framework/generated jobs. `safe-outputs.runs-on` still takes precedence over `runs-on-slim` for safe-output jobs specifically.
+
 ## Related documentation
 
-- [Frontmatter](/gh-aw/reference/frontmatter/#run-configuration-run-name-runs-on-timeout-minutes) — `runs-on` syntax reference
+- [Frontmatter](/gh-aw/reference/frontmatter/#run-configuration-run-name-runs-on-runs-on-slim-timeout-minutes) — `runs-on` and `runs-on-slim` syntax reference
 - [Imports](/gh-aw/reference/imports/) — importable fields and merge semantics
 - [Threat Detection](/gh-aw/reference/threat-detection/) — detection job configuration
 - [Network Access](/gh-aw/reference/network/) — configuring outbound network permissions
diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md
index 32759f50752..70ce246e34e 100644
--- a/docs/src/content/docs/reference/frontmatter.md
+++ b/docs/src/content/docs/reference/frontmatter.md
@@ -467,16 +467,19 @@ Enables defining custom MCP tools inline using JavaScript or shell scripts. See
 
 Enables automatic issue creation, comment posting, and other safe outputs. See [Safe Outputs Processing](/gh-aw/reference/safe-outputs/).
 
-### Run Configuration (`run-name:`, `runs-on:`, `timeout-minutes:`)
+### Run Configuration (`run-name:`, `runs-on:`, `runs-on-slim:`, `timeout-minutes:`)
 
 Standard GitHub Actions properties:
 
 ```yaml wrap
 run-name: "Custom workflow run name"  # Defaults to workflow name
 runs-on: ubuntu-latest               # Defaults to ubuntu-latest (main job only)
+runs-on-slim: ubuntu-slim            # Defaults to ubuntu-slim (framework jobs only)
 timeout-minutes: 30                  # Defaults to 20 minutes
 ```
 
+`runs-on` applies to the main agent job only. `runs-on-slim` applies to all framework/generated jobs (activation, safe-outputs, unlock, etc.) and defaults to `ubuntu-slim`. `safe-outputs.runs-on` takes precedence over `runs-on-slim` for safe-output jobs specifically.
+
 **Supported runners for `runs-on:`**
 
 | Runner | Status |
diff --git a/docs/src/content/docs/reference/safe-outputs.md b/docs/src/content/docs/reference/safe-outputs.md
index c3f08a4eacf..0024a9c043b 100644
--- a/docs/src/content/docs/reference/safe-outputs.md
+++ b/docs/src/content/docs/reference/safe-outputs.md
@@ -1482,7 +1482,17 @@ safe-outputs:
 
 ### Custom Runner Image
 
-Specify custom runner for safe output jobs (default: `ubuntu-slim`): `runs-on: ubuntu-22.04`
+Specify a custom runner for safe output jobs (default: `ubuntu-slim`):
+
+```aw
+---
+safe-outputs:
+  runs-on: ubuntu-22.04
+  create-issue: {}
+---
+```
+
+`safe-outputs.runs-on` overrides `runs-on-slim:` for safe-output jobs specifically. To override the runner for all framework jobs at once, use the top-level [`runs-on-slim:`](/gh-aw/guides/self-hosted-runners/#configuring-the-framework-job-runner) field instead.
 
 ### Safe Outputs Job Concurrency (`concurrency-group:`)
 
