From 524c95acc3d6061cf5bddba5c2070b31071fc11d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Jun 2026 18:46:24 +0000
Subject: [PATCH 1/5] Initial plan


From 669f7d272b6d2b6a057d4ac3434b002ad35cea38 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Jun 2026 18:59:43 +0000
Subject: [PATCH 2/5] Plan minimal runner-spec parity changes

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .github/workflows/pr-code-quality-reviewer.lock.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/pr-code-quality-reviewer.lock.yml b/.github/workflows/pr-code-quality-reviewer.lock.yml
index 40f9477777c..5c633517b95 100644
--- a/.github/workflows/pr-code-quality-reviewer.lock.yml
+++ b/.github/workflows/pr-code-quality-reviewer.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"661ab4bd42bd83eff79d7d460f50a12e3cee567ac434b2d37a2480d9a0e20965","body_hash":"4d3260d49c3010a13ea7c49bba10f51f2b9f1c1473ceca69008cfe766a9b273c","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.63","copilot-sdk":"1.0.1"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"57c59bcb86591e8b21ad20298687f8d1adf895d5c4cf6f909d3339905428cc28","body_hash":"4d3260d49c3010a13ea7c49bba10f51f2b9f1c1473ceca69008cfe766a9b273c","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.63","copilot-sdk":"1.0.1"}}
 # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/cache/save","sha":"27d5ce7f107fe9357f9df03efb73ab90386fccae","version":"v5.0.5"},{"repo":"actions/checkout","sha":"df4cb1c069e1874edd31b4311f1884172cec0e10","version":"v6.0.3"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4","digest":"sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.4@sha256:b268ebf37df2428b19efcb383f001d65dc6a5ec10af43feb886d1a8477ab0e3a"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4","digest":"sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.4@sha256:3ea0d12a2d124db8ed6e2d18aff040e30ab3568161f258a132fccdeede4198cd"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.4","digest":"sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.4@sha256:72c378c029d2fad4684847ab44c329e526ac6b1a78cdf97656870ea11d201545"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4","digest":"sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.4@sha256:87979038897e40caed22245b64d1daa796390d2dca289b99d3d1174c85740af8"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.26","digest":"sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.26@sha256:d3b03f54eee3a8176818c9a52087623e45b7f644a28814337fcc0838e2534490"},{"image":"ghcr.io/github/github-mcp-server:v1.3.0","digest":"sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80","pinned_image":"ghcr.io/github/github-mcp-server:v1.3.0@sha256:5c83359327a0bacc3d34db730bea6557d39d341cee0bf6c58c9a896e33150e80"}]}
 # This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
 #

From c1502ced742fc787f35c45618ae60ccacbc3ab68 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Jun 2026 19:25:56 +0000
Subject: [PATCH 3/5] Support array and object runner specs across slim and
 safe-output runs-on fields

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 docs/public/editor/autocomplete-data.json     |   16 +-
 .../docs/reference/frontmatter-full.md        | 1224 +++++++++++++++--
 .../src/content/docs/reference/frontmatter.md |    2 +-
 .../content/docs/reference/safe-outputs.md    |    2 +-
 .../docs/reference/self-hosted-runners.md     |    5 +-
 pkg/parser/schema_location_test.go            |   35 +
 pkg/parser/schemas/main_workflow_schema.json  |   24 +-
 .../central_slash_command_workflow.go         |    2 +-
 pkg/workflow/frontmatter_parsing.go           |   10 +
 pkg/workflow/frontmatter_types_test.go        |   34 +
 pkg/workflow/imports.go                       |    2 +-
 pkg/workflow/runs_on_snippet.go               |   29 +
 pkg/workflow/runs_on_unmarshal.go             |   42 +
 pkg/workflow/runs_on_validation.go            |   49 +-
 pkg/workflow/runs_on_validation_test.go       |   34 +
 pkg/workflow/safe_outputs_config.go           |    4 +-
 pkg/workflow/safe_outputs_import_test.go      |    4 +-
 pkg/workflow/safe_outputs_runs_on_test.go     |   50 +-
 pkg/workflow/safe_outputs_runtime.go          |    2 +-
 pkg/workflow/threat_detection.go              |    6 +-
 pkg/workflow/threat_detection_test.go         |   27 +-
 21 files changed, 1455 insertions(+), 148 deletions(-)
 create mode 100644 pkg/workflow/runs_on_snippet.go
 create mode 100644 pkg/workflow/runs_on_unmarshal.go

diff --git a/docs/public/editor/autocomplete-data.json b/docs/public/editor/autocomplete-data.json
index c1b1597ca35..f5776fc686a 100644
--- a/docs/public/editor/autocomplete-data.json
+++ b/docs/public/editor/autocomplete-data.json
@@ -1944,9 +1944,21 @@
           "leaf": true
         },
         "runs-on": {
-          "type": "string",
+          "type": "string|array|object",
           "desc": "Runner specification for all safe-outputs jobs (activation, create-issue, add-comment, etc.).",
-          "leaf": true
+          "children": {
+            "group": {
+              "type": "string",
+              "desc": "Runner group name for self-hosted runners or GitHub-hosted runner groups",
+              "leaf": true
+            },
+            "labels": {
+              "type": "array",
+              "desc": "List of runner labels for self-hosted runners or GitHub-hosted runner selection",
+              "array": true
+            }
+          },
+          "array": true
         },
         "steps": {
           "type": "array",
diff --git a/docs/src/content/docs/reference/frontmatter-full.md b/docs/src/content/docs/reference/frontmatter-full.md
index 789f70450e0..2b00d013eef 100644
--- a/docs/src/content/docs/reference/frontmatter-full.md
+++ b/docs/src/content/docs/reference/frontmatter-full.md
@@ -946,24 +946,21 @@ on:
   skip-author-associations:
     {}
 
-  # Exact-match allowlist of repository roles required to trigger agentic workflows.
-  # Each entry is matched literally — there is no privilege hierarchy. Defaults to
+  # Repository access roles required to trigger agentic workflows. Defaults to
   # ['admin', 'maintainer', 'write'] for security. Use 'all' to allow any
   # authenticated user (⚠️ security consideration).
-  # ⚠️ roles: [write] rejects actors with 'admin' or 'maintainer' roles because
-  # matching is exact, not a minimum threshold. List every role you want to accept.
   # (optional)
   # Accepted formats:
 
-  # Format 1: Single repository role that can trigger the workflow. Use
+  # Format 1: Single repository permission level that can trigger the workflow. Use
   # 'all' to allow any authenticated user (⚠️ disables permission checking entirely
   # - use with caution)
   roles: "admin"
 
-  # Format 2: Exact-match allowlist of repository roles that can trigger the workflow.
+  # Format 2: List of repository permission levels that can trigger the workflow.
   # Permission checks are automatically applied to potentially unsafe triggers.
   roles: []
-    # Array items: Repository role (exact match): 'admin' (full access),
+    # Array items: Repository permission level: 'admin' (full access),
     # 'maintainer'/'maintain' (repository management), 'write' (push access), 'triage'
     # (issue management), 'read' (read-only access)
 
@@ -1411,6 +1408,11 @@ permissions:
   # (optional)
   checks: "read"
 
+  # Permission level for Copilot requests (write/none only). Set to write to allow
+  # Copilot inference via the GitHub Actions token.
+  # (optional)
+  copilot-requests: "write"
+
   # Permission for repository contents (read: view files, write: modify
   # files/branches, none: no access)
   # (optional)
@@ -1542,13 +1544,39 @@ runs-on:
 
 # 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
+# generated job runners without requiring a safe-outputs section. Supports the
+# same string, array, and runner-group object forms as runs-on. 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.
 # (optional)
+# Accepted formats:
+
+# Format 1: Simple runner label string. Use for standard GitHub-hosted runners
+# (e.g., 'ubuntu-latest', 'windows-latest', 'macos-latest') or self-hosted runner
+# labels. Most common form for agentic workflows.
 runs-on-slim: "example-value"
 
+# Format 2: Array of runner labels for selection with fallbacks. GitHub Actions
+# will use the first available runner that matches any label in the array. Useful
+# for high-availability setups or when multiple runner types are acceptable.
+runs-on-slim: []
+  # Array items: string
+
+# Format 3: Runner group configuration for GitHub-hosted runners. Use this form to
+# target specific runner groups (e.g., larger runners with more CPU/memory) or
+# self-hosted runner pools with specific label requirements. Agentic workflows may
+# benefit from larger runners for complex AI processing tasks.
+runs-on-slim:
+  # Runner group name for self-hosted runners or GitHub-hosted runner groups
+  # (optional)
+  group: "example-value"
+
+  # List of runner labels for self-hosted runners or GitHub-hosted runner selection
+  # (optional)
+  labels: []
+    # Array of strings
+
 # Workflow timeout in minutes (GitHub Actions standard field). Defaults to 20
 # minutes for agentic workflows. Has sensible defaults and can typically be
 # omitted. Custom runners support longer timeouts beyond the GitHub-hosted runner
@@ -1560,8 +1588,7 @@ runs-on-slim: "example-value"
 # Format 1: integer
 timeout-minutes: 1
 
-# Format 2: GitHub Actions expression that resolves to an integer (e.g. '${{
-# inputs.timeout }}')
+# Format 2: GitHub Actions expression that resolves to an integer at runtime
 timeout-minutes: "example-value"
 
 # Concurrency control to limit concurrent workflow runs (GitHub Actions standard
@@ -1636,17 +1663,15 @@ env: "example-value"
 features:
   {}
 
-# Named model alias definitions with ordered fallback lists, resolved recursively
-# by AWF. Each key is an alias name (use empty string "" for the default policy).
-# Each value is an ordered list of vendor/modelid glob patterns or other alias
-# names to try in sequence. Entries defined here are merged on top of the builtin
-# aliases; the main workflow file always wins over imported aliases. Builtin
-# aliases include: sonnet, sonnet-6x, haiku, opus, gpt-5, gpt-5-mini, gpt-5-codex,
-# gemini-flash, gemini-pro, small, mini, large, auto, any, agent, copilot, claude,
-# codex, gemini.
+# Custom model pricing data in the same structure as models.json. Merged with the
+# built-in models.json at runtime; frontmatter entries override matching models
+# and fill gaps for unknown models. Useful for custom or private models, or to
+# adjust pricing for AI Credits cost accounting.
 # (optional)
 models:
-  {}
+  # Provider-keyed map of model pricing data.
+  providers:
+    {}
 
 # A/B testing experiments. Each key is an experiment name; the value is either an
 # array of two or more variant strings (bare-array form) or an object with a
@@ -1667,17 +1692,12 @@ experiments:
   # Storage backend for experiment state. 'repo' (default) persists state to a git
   # branch named 'experiments/{sanitizedWorkflowID}' (workflow ID lowercased with
   # hyphens removed, e.g. 'my-workflow' -> 'experiments/myworkflow') for durability
-  # across cache evictions. 'cache' uses GitHub Actions cache (legacy behavior).
+  # across cache evictions. 'cache' uses GitHub Actions cache (legacy behaviour).
   # Repo storage is recommended because experiment data is valuable and more durable
   # than cache.
   # (optional)
   storage: "cache"
 
-# Controls whether the custom agent should disable model invocation. When set to
-# true, the agent will not make additional model calls.
-# (optional)
-disable-model-invocation: true
-
 # Secret values passed to workflow execution. Secrets can be defined as simple
 # strings (GitHub Actions expressions) or objects with 'value' and 'description'
 # properties. Typically used to provide secrets to MCP servers or custom engines.
@@ -2092,18 +2112,6 @@ engine:
   # (optional)
   permission-mode: "auto"
 
-  # Maximum number of chat iterations per run. Helps prevent runaway loops and
-  # control costs. Has sensible defaults and can typically be omitted. Note: Only
-  # supported by the claude engine.
-  # (optional)
-  # Accepted formats:
-
-  # Format 1: Maximum number of chat iterations per run as an integer value
-  max-turns: 1
-
-  # Format 2: Maximum number of chat iterations per run as a string value
-  max-turns: "example-value"
-
   # Maximum number of continuations for multi-run autopilot mode. Default is 1
   # (single run, no autopilot). Values greater than 1 enable --autopilot mode for
   # the copilot engine with --max-autopilot-continues set to this value. Note: Only
@@ -2229,9 +2237,9 @@ engine:
   # (optional)
   api-target: "example-value"
 
-  # Custom model token weights for legacy Effective Tokens (ET) computation. Overrides or extends
-  # the built-in model multipliers from model_multipliers.json. Useful for custom
-  # models or adjusted cost ratios.
+  # Custom model token weights for AI Credits cost ratio adjustment. Overrides or
+  # extends built-in model cost defaults. Useful for custom models or adjusted cost
+  # ratios.
   # (optional)
   token-weights:
     # Per-model cost multipliers relative to the reference model (claude-sonnet-4.5 =
@@ -2306,9 +2314,11 @@ engine:
   # (optional)
   copilot-sdk: true
 
-  # Custom Node.js Copilot SDK driver script filename (copilot engine only). This is
-  # only used when copilot-sdk: true is set and must be a safe basename ending with
-  # .js, .cjs, or .mjs.
+  # Custom Copilot SDK driver script or command (copilot engine only). Setting this
+  # field implies `copilot-sdk: true`. Accepts a relative path from the workspace
+  # root with a supported language extension (.js, .cjs, .mjs, .py, .ts, .mts, .rb),
+  # e.g. `.github/drivers/my_driver.py`, or a bare command name without an extension
+  # for an arbitrary executable in PATH.
   # (optional)
   copilot-sdk-driver: "example-value"
 
@@ -2532,42 +2542,57 @@ engine:
   # the default engine when engine.id is not specified.
   model: "example-value"
 
-# Explicit AI Credits budget control for firewall cost enforcement. Omit this
-# field to leave AIC budget protection unset. Set to -1 to disable budget
-# enforcement.
+# AWF turn cap (`max_turns`) applied consistently across all agentic engines.
+# Supports GitHub Actions expressions (e.g. '${{ inputs.max-turns }}') for
+# reusable workflow_call workflows.
 # (optional)
 # Accepted formats:
 
-# Format 1: Maximum AI Credits (AIC) budget for AWF API proxy enforcement.
-max-ai-credits: 1
+# Format 1: integer
+max-turns: 1
 
-# Format 2: Maximum AI Credits (AIC) budget as a numeric string with optional
-# K/M suffix or GitHub Actions expression.
-max-ai-credits: "example-value"
+# Format 2: GitHub Actions expression that resolves to an integer at runtime
+max-turns: "example-value"
 
-# Explicit daily AI Credits guardrail per workflow across the previous 24-hour
-# window. Omit to disable, or set to -1 to explicitly disable.
+# Copilot SDK safeguard threshold for repeated tool denials before stopping
+# inference. Defaults to 5 when omitted. Supports GitHub Actions expressions (for
+# example, '${{ inputs.max-tool-denials }}'). Supported only with engine 'copilot'
+# and engine.copilot-sdk: true.
 # (optional)
 # Accepted formats:
 
-# Format 1: Maximum daily AI Credits (AIC) budget.
-max-daily-ai-credits: 1
+# Format 1: integer
+max-tool-denials: 1
 
-# Format 2: Maximum daily AI Credits (AIC) budget as a numeric string with
-# optional K/M suffix or GitHub Actions expression.
-max-daily-ai-credits: "example-value"
+# Format 2: GitHub Actions expression that resolves to an integer at runtime
+max-tool-denials: "example-value"
 
-# DEPRECATED: Legacy alias for AWF invocation cap (`apiProxy.maxRuns`).
-# Use `max-turns` instead. Defaults to 500 when omitted.
+# Per-run AI Credits budget control for firewall cost enforcement. Enabled by
+# default at 1000 (1k) when omitted. Set to -1 to disable both budget enforcement
+# and token steering. Supports GitHub Actions expressions.
 # (optional)
 # Accepted formats:
 
-# Format 1: Maximum number of LLM invocations allowed per run.
-max-turns: 1
+# Format 1: Configuration object
 
-# Format 2: Maximum number of LLM invocations allowed per run as a numeric string
-# or GitHub Actions expression.
-max-turns: "example-value"
+# Format 2: integer
+max-ai-credits: 1
+
+# Format 3: string
+max-ai-credits: "example-value"
+
+# 24-hour AI Credits guardrail for runs triggered by the same user. Omit the field
+# to leave the guardrail disabled. Supports GitHub Actions expressions.
+# (optional)
+# Accepted formats:
+
+# Format 1: Configuration object
+
+# Format 2: integer
+max-daily-ai-credits: 1
+
+# Format 3: string
+max-daily-ai-credits: "example-value"
 
 # MCP server definitions
 # (optional)
@@ -3100,10 +3125,9 @@ tools:
     # (optional)
     restore-only: true
 
-    # Cache restore key scope: 'workflow' (default, restores from same workflow key
-    # lineage) or 'repo' (adds repository-wide restore keys). Scope broadens
-    # cross-workflow matching but cache visibility remains branch-scoped (with
-    # GitHub's default-branch restore fallback behavior).
+    # Cache restore key scope: 'workflow' (default, only restores from same workflow)
+    # or 'repo' (restores from any workflow in the repository). Use 'repo' with
+    # caution as it allows cross-workflow cache sharing.
     # (optional)
     scope: "workflow"
 
@@ -3170,6 +3194,24 @@ tools:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable (true) or disable (false) comment-memory.
   comment-memory: true
 
@@ -3509,6 +3551,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable issue creation with default configuration
   create-issue: null
 
@@ -3560,6 +3620,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable agent session creation with default configuration
   create-agent-task: null
 
@@ -3611,6 +3689,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable agent session creation with default configuration
   create-agent-session: null
 
@@ -3723,6 +3819,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable project management with default configuration (max=10)
   update-project: null
 
@@ -3817,6 +3931,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable project creation with default configuration (max=1)
   create-project: null
 
@@ -3862,6 +3994,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable project status updates with default configuration (max=1)
   create-project-status-update: null
 
@@ -3988,6 +4138,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable discussion creation with default configuration
   create-discussion: null
 
@@ -4033,11 +4201,35 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that discussions can be
+    # closed in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # If true, emit step summary messages instead of making GitHub API calls for this
     # specific output type (preview mode)
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable discussion closing with default configuration
   close-discussion: null
 
@@ -4089,6 +4281,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that discussions can be
+    # updated in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # Controls whether AI-generated footer is added when updating the discussion body.
     # When false, the visible footer content is omitted. Defaults to true. Only
     # applies when 'body' is enabled.
@@ -4100,6 +4298,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -4159,6 +4375,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # Reason for closing the issue (default: completed)
     # (optional)
     state-reason: "completed"
@@ -4204,6 +4438,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that pull requests can be
+    # closed in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -4214,6 +4454,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable pull request closing with default configuration
   close-pull-request: null
 
@@ -4255,6 +4513,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that pull requests can be
+    # marked as ready in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -4265,6 +4529,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable marking pull requests as ready for review with default
   # configuration
   mark-pull-request-as-ready-for-review: null
@@ -4318,16 +4600,33 @@ safe-outputs:
 
     # When true, minimizes/hides all previous comments from the same agentic workflow
     # (identified by tracker-id) before creating the new comment. Supports literal
-    # boolean or GitHub Actions expression (e.g. '${{ inputs.hide-older-comments }}').
-    # Default: false.
+    # boolean, GitHub Actions expression (e.g. '${{ inputs.hide-older-comments }}'),
+    # or object form for advanced matching. Default: false.
     # (optional)
     # Accepted formats:
 
-    # Format 1: boolean
-    hide-older-comments: true
+    # Format 1: A boolean value that may also be specified as a GitHub Actions
+    # expression string that resolves to a boolean at runtime (e.g. '${{
+    # inputs.my-flag }}').
 
-    # Format 2: GitHub Actions expression that resolves to a boolean at runtime
-    hide-older-comments: "example-value"
+    # Format 2: object
+    hide-older-comments:
+      # Enable or disable hide-older-comments when using object form. Defaults to true
+      # when omitted.
+      # (optional)
+      # Accepted formats:
+
+      # Format 1: boolean
+      enabled: true
+
+      # Format 2: GitHub Actions expression that resolves to a boolean at runtime
+      enabled: "example-value"
+
+      # Additional workflow-id values to fully match when selecting older comments to
+      # hide.
+      # (optional)
+      match: []
+        # Array of strings
 
     # List of allowed reasons for hiding older comments when hide-older-comments is
     # enabled. Default: all reasons allowed (spam, abuse, off_topic, outdated,
@@ -4382,6 +4681,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable issue comment creation with default configuration
   add-comment: null
 
@@ -4507,7 +4824,9 @@ safe-outputs:
     allow-empty: true
 
     # Target repository in format 'owner/repo' for cross-repository pull request
-    # creation. Takes precedence over trial target repo settings.
+    # creation, or '*' to let the agent choose the target repository at runtime
+    # (requires checkout: configs with path: for each possible target). Takes
+    # precedence over trial target repo settings.
     # (optional)
     target-repo: "example-value"
 
@@ -4593,7 +4912,7 @@ safe-outputs:
 
     # Maximum allowed size for git patches in kilobytes (KB) for create-pull-request
     # only. Overrides safe-outputs max-patch-size for this output type. Defaults to
-    # 4096 KB (4 MB) when unset.
+    # 1024 KB (1 MB) when unset.
     # (optional)
     max-patch-size: 1
 
@@ -4624,6 +4943,20 @@ safe-outputs:
     # (optional)
     auto-close-issue: null
 
+    # When true, automatically close older open pull requests with the same
+    # workflow-id marker (or close-older-key when set) with a comment linking to the
+    # new PR. Maximum 10 PRs will be closed. Only runs if PR creation succeeds.
+    # (optional)
+    close-older-pull-requests: null
+
+    # Optional explicit deduplication key for close-older-pull-requests matching. When
+    # set, a `<!-- gh-aw-close-key: <value> -->` marker is embedded in the PR body and
+    # used as the primary key for searching and filtering older PRs instead of the
+    # workflow-id markers. The value is normalized to identifier style (lowercase
+    # alphanumeric, dashes, underscores).
+    # (optional)
+    close-older-key: "example-value"
+
     # Token used to push an empty commit after PR creation to trigger CI events. Works
     # around the GITHUB_TOKEN limitation where pushes don't trigger workflow runs.
     # Defaults to the magic secret GH_AW_CI_TRIGGER_TOKEN if set in the repository.
@@ -4741,27 +5074,29 @@ safe-outputs:
     # (optional)
     signed-commits: true
 
-    # When true, automatically close older open pull requests from the same workflow
-    # (identified by the workflow-id marker in the PR body) with a comment linking to
-    # the new PR. Searches for open PRs containing the workflow-id marker. Maximum 10
-    # pull requests will be closed. Only runs if PR creation succeeds.
-    # (optional)
-    close-older-pull-requests: true
-
-    # Optional explicit deduplication key for close-older matching. When set, a `<!--
-    # gh-aw-close-key: <value> -->` marker is embedded in the PR body and used as the
-    # primary key for searching and filtering older pull requests instead of the
-    # workflow-id markers. This gives deterministic isolation across caller workflows
-    # and is stable across workflow renames. The value is normalized to identifier
-    # style (lowercase alphanumeric, dashes, underscores).
-    # (optional)
-    close-older-key: "example-value"
-
     # If true, emit step summary messages instead of making GitHub API calls for this
     # specific output type (preview mode)
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # When true, adds workflows: write to the GitHub App token permissions. Required
     # when allowed-files targets .github/workflows/ paths. Requires
     # safe-outputs.github-app to be configured because the workflows permission is a
@@ -4823,6 +5158,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -4918,6 +5271,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -4977,6 +5348,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -4991,14 +5380,16 @@ safe-outputs:
   # Format 2: Enable with default configuration
   reply-to-pull-request-review-comment: null
 
-  # Enable AI agents to resolve review threads on the triggering pull request after
-  # addressing feedback.
+  # Enable AI agents to resolve review threads on pull requests after addressing
+  # feedback. Supports cross-repository resolution via target, target-repo, and
+  # allowed-repos.
   # (optional)
   # Accepted formats:
 
-  # Format 1: Configuration for resolving review threads on pull requests.
-  # Resolution is scoped to the triggering PR only — threads on other PRs cannot be
-  # resolved.
+  # Format 1: Configuration for resolving review threads on pull requests. By
+  # default, resolution is scoped to the triggering PR only. When target,
+  # target-repo, or allowed-repos are specified, cross-repository thread resolution
+  # is supported.
   resolve-pull-request-review-thread:
     # Maximum number of review threads to resolve (default: 10) Supports integer or
     # GitHub Actions expression (e.g. '${{ inputs.max }}').
@@ -5011,6 +5402,26 @@ safe-outputs:
     # Format 2: GitHub Actions expression that resolves to an integer at runtime
     max: "example-value"
 
+    # Target PR for thread resolution: 'triggering' (default, current PR), '*' (any
+    # PR, requires pull_request_number in agent output), or explicit PR number (e.g.
+    # ${{ github.event.inputs.pr_number }}). Required when workflow is not triggered
+    # by a pull request (e.g. workflow_dispatch).
+    # (optional)
+    target: "example-value"
+
+    # Target repository in format 'owner/repo' for cross-repository PR review thread
+    # resolution. Takes precedence over trial target repo settings.
+    # (optional)
+    target-repo: "example-value"
+
+    # List of additional repositories in format 'owner/repo' that PR review threads
+    # can be resolved in. When specified, the agent can use a 'repo' field in the
+    # output to specify which repository to resolve threads in. The target repository
+    # (current or target-repo) is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -5021,6 +5432,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -5082,6 +5511,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable code scanning alert creation with default configuration
   # (unlimited findings)
   create-code-scanning-alert: null
@@ -5114,6 +5561,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable code scanning autofix creation with default configuration (max:
   # 10)
   autofix-code-scanning-alert: null
@@ -5152,6 +5617,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # GitHub App credentials for minting an installation access token scoped to
     # checks:write for this handler. When set, a short-lived token is minted before
     # the handler runs and revoked afterwards.
@@ -5439,6 +5922,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Enable AI agents to remove labels from GitHub issues or pull requests.
   # (optional)
   # Accepted formats:
@@ -5512,6 +6013,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Enable AI agents to request reviews from users or teams on pull requests based
   # on code changes or expertise matching.
   # (optional)
@@ -5562,6 +6081,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that reviewers can be
+    # added in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -5572,6 +6097,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -5611,11 +6154,22 @@ safe-outputs:
     # Format 2: GitHub Actions expression that resolves to an integer at runtime
     max: "example-value"
 
+    # Target for milestone assignment: 'triggering' (default, current issue/PR), '*'
+    # (any issue/PR), or explicit number.
+    # (optional)
+    target: "example-value"
+
     # Target repository in format 'owner/repo' for cross-repository milestone
     # assignment. Takes precedence over trial target repo settings.
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that milestone
+    # assignments can target. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -5626,6 +6180,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -5698,6 +6270,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that agents can be
+    # assigned in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # Target repository where the pull request should be created, in format
     # 'owner/repo'. If omitted, the PR will be created in the same repository as the
     # issue (specified by target-repo or the workflow's repository). This allows
@@ -5736,6 +6314,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Enable AI agents to assign issues or pull requests to specific GitHub users
   # based on workflow logic or expertise matching.
   # (optional)
@@ -5802,6 +6398,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -5874,6 +6488,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -5907,6 +6539,11 @@ safe-outputs:
     # Format 2: GitHub Actions expression that resolves to an integer at runtime
     max: "example-value"
 
+    # Target for sub-issue linking: 'triggering' (default, current issue), '*' (any
+    # issue), or explicit issue number.
+    # (optional)
+    target: "example-value"
+
     # Optional list of labels that parent issues must have to be eligible for linking
     # (optional)
     parent-required-labels: []
@@ -5930,6 +6567,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that sub-issue linking
+    # can target. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -5940,6 +6583,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Enable AI agents to edit and update existing GitHub issue content, titles,
   # labels, assignees, and metadata.
   # (optional)
@@ -6011,6 +6672,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -6078,6 +6757,12 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that pull requests can be
+    # updated in. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # GitHub token to use for this specific output type. Overrides global github-token
     # if specified.
     # (optional)
@@ -6088,6 +6773,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -6222,7 +6925,7 @@ safe-outputs:
 
     # Maximum allowed size for git patches in kilobytes (KB) for
     # push-to-pull-request-branch only. Overrides safe-outputs max-patch-size for this
-    # output type. Defaults to 4096 KB (4 MB) when unset.
+    # output type. Defaults to 1024 KB (1 MB) when unset.
     # (optional)
     max-patch-size: 1
 
@@ -6236,6 +6939,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # Token used to push an empty commit after pushing changes to trigger CI events.
     # Works around the GITHUB_TOKEN limitation where pushes don't trigger workflow
     # runs. Defaults to the magic secret GH_AW_CI_TRIGGER_TOKEN if set in the
@@ -6259,7 +6980,9 @@ safe-outputs:
     signed-commits: true
 
     # Target repository in format 'owner/repo' for cross-repository push to pull
-    # request branch. Takes precedence over trial target repo settings.
+    # request branch, or '*' to let the agent choose the target repository at runtime
+    # (requires checkout: configs with path: for each possible target). Takes
+    # precedence over trial target repo settings.
     # (optional)
     target-repo: "example-value"
 
@@ -6397,11 +7120,22 @@ safe-outputs:
     # Format 2: GitHub Actions expression that resolves to an integer at runtime
     max: "example-value"
 
+    # Target for comment hiding: 'triggering' (default, current issue/PR), '*' (any
+    # item), or explicit number.
+    # (optional)
+    target: "example-value"
+
     # Target repository in format 'owner/repo' for cross-repository comment hiding.
     # Takes precedence over trial target repo settings.
     # (optional)
     target-repo: "example-value"
 
+    # List of additional repositories in format 'owner/repo' that comment hiding can
+    # target. The target repository is always implicitly allowed.
+    # (optional)
+    allowed-repos: []
+      # Array of strings
+
     # List of allowed reasons for hiding comments. Default: all reasons allowed (spam,
     # abuse, off_topic, outdated, resolved, low_quality).
     # (optional)
@@ -6420,6 +7154,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -6487,6 +7239,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -6553,6 +7323,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
     # All of these labels must be present on the target item for this operation to
     # proceed
     # (optional)
@@ -6599,6 +7387,20 @@ safe-outputs:
     # (optional)
     target-repo: "example-value"
 
+    # List of repositories in format 'owner/repo' that cross-repository workflow
+    # dispatch may target. Supports arrays and GitHub Actions expressions resolving to
+    # a comma-separated list (e.g. '${{ inputs['allowed-repos'] }}').
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    allowed-repos: []
+      # Array items: string
+
+    # Format 2: GitHub Actions expression resolving to a comma-separated list of
+    # repository slugs (e.g. '${{ inputs['allowed-repos'] }}')
+    allowed-repos: "example-value"
+
     # Git ref (branch, tag, or SHA) to use when dispatching the workflow. For
     # workflow_call relay scenarios this is auto-injected by the compiler from
     # needs.activation.outputs.target_ref. Overrides the caller's GITHUB_REF.
@@ -6610,6 +7412,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Shorthand array format: list of workflow names (without .md extension)
   # to allow dispatching
   dispatch-workflow: []
@@ -6658,6 +7478,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Shorthand array format: list of workflow names (without .md extension)
   # to allow calling
   call-workflow: []
@@ -6713,6 +7551,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable missing tool reporting with default configuration
   missing-tool: null
 
@@ -6772,6 +7628,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable missing data reporting with default configuration
   missing-data: null
 
@@ -6813,6 +7687,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable noop output with default configuration (max: 1)
   noop: null
 
@@ -6861,6 +7753,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable asset publishing with default configuration
   upload-asset: null
 
@@ -6927,7 +7837,7 @@ safe-outputs:
     # Default values injected when the model omits a field
     # (optional)
     defaults:
-      # Behavior when no files match: 'error' (default) or 'ignore'
+      # Behaviour when no files match: 'error' (default) or 'ignore'
       # (optional)
       if-no-files: "error"
 
@@ -6977,6 +7887,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable release updates with default configuration
   update-release: null
 
@@ -7189,7 +8117,7 @@ safe-outputs:
       # (optional)
       workflows: "read"
 
-  # Maximum allowed size for git patches in kilobytes (KB). Defaults to 4096 KB (4
+  # Maximum allowed size for git patches in kilobytes (KB). Defaults to 1024 KB (1
   # MB). If patch exceeds this size, the job will fail.
   # (optional)
   max-patch-size: 1
@@ -7251,11 +8179,52 @@ safe-outputs:
     # (optional)
     post-steps: []
 
+    # Per-run AI Credits budget for threat-detection engine execution. Accepts numeric
+    # values only (expressions are not supported). When unset, gh-aw emits a runtime
+    # default expression `${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400'
+    # }}`.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: Configuration object
+
+    # Format 2: integer
+    max-ai-credits: 1
+
+    # Format 3: string
+    max-ai-credits: "example-value"
+
     # Runner specification for the detection job. Overrides agent.runs-on for the
-    # detection job only. Defaults to agent.runs-on.
+    # detection job only. Supports string, array, or runner-group object forms.
+    # Defaults to agent.runs-on.
     # (optional)
+    # Accepted formats:
+
+    # Format 1: Simple runner label string. Use for standard GitHub-hosted runners
+    # (e.g., 'ubuntu-latest', 'windows-latest', 'macos-latest') or self-hosted runner
+    # labels. Most common form for agentic workflows.
     runs-on: "example-value"
 
+    # Format 2: Array of runner labels for selection with fallbacks. GitHub Actions
+    # will use the first available runner that matches any label in the array. Useful
+    # for high-availability setups or when multiple runner types are acceptable.
+    runs-on: []
+      # Array items: string
+
+    # Format 3: Runner group configuration for GitHub-hosted runners. Use this form to
+    # target specific runner groups (e.g., larger runners with more CPU/memory) or
+    # self-hosted runner pools with specific label requirements. Agentic workflows may
+    # benefit from larger runners for complex AI processing tasks.
+    runs-on:
+      # Runner group name for self-hosted runners or GitHub-hosted runner groups
+      # (optional)
+      group: "example-value"
+
+      # List of runner labels for self-hosted runners or GitHub-hosted runner selection
+      # (optional)
+      labels: []
+        # Array of strings
+
     # When true (default), detection failures produce warnings and allow safe outputs
     # to proceed with a caution notice and 'needs-review' label. When false, detection
     # failures block safe outputs entirely. Accepts a boolean literal or a GitHub
@@ -7501,7 +8470,7 @@ safe-outputs:
   # for workflows with many sequential safe output operations (e.g.
   # push_to_pull_request_branch against large repositories).
   # (optional)
-  timeout-minutes: 120
+  timeout-minutes: 1
 
   # Explicit additional custom workflow jobs that the consolidated safe_outputs job
   # should depend on.
@@ -7529,12 +8498,37 @@ safe-outputs:
     url: "example-value"
 
   # Runner specification for all safe-outputs jobs (activation, create-issue,
-  # add-comment, etc.). Single runner label (e.g., 'ubuntu-slim', 'ubuntu-latest',
-  # 'windows-latest', 'self-hosted'). Defaults to 'ubuntu-slim'. See
+  # add-comment, etc.). Supports string, array, or runner-group object forms.
+  # Defaults to 'ubuntu-slim'. See
   # https://github.blog/changelog/2025-10-28-1-vcpu-linux-runner-now-available-in-github-actions-in-public-preview/
   # (optional)
+  # Accepted formats:
+
+  # Format 1: Simple runner label string. Use for standard GitHub-hosted runners
+  # (e.g., 'ubuntu-latest', 'windows-latest', 'macos-latest') or self-hosted runner
+  # labels. Most common form for agentic workflows.
   runs-on: "example-value"
 
+  # Format 2: Array of runner labels for selection with fallbacks. GitHub Actions
+  # will use the first available runner that matches any label in the array. Useful
+  # for high-availability setups or when multiple runner types are acceptable.
+  runs-on: []
+    # Array items: string
+
+  # Format 3: Runner group configuration for GitHub-hosted runners. Use this form to
+  # target specific runner groups (e.g., larger runners with more CPU/memory) or
+  # self-hosted runner pools with specific label requirements. Agentic workflows may
+  # benefit from larger runners for complex AI processing tasks.
+  runs-on:
+    # Runner group name for self-hosted runners or GitHub-hosted runner groups
+    # (optional)
+    group: "example-value"
+
+    # List of runner labels for self-hosted runners or GitHub-hosted runner selection
+    # (optional)
+    labels: []
+      # Array of strings
+
   # Custom steps to inject into all safe-output jobs. These steps run after checking
   # out the repository and setting up the action, and before any safe-output code
   # executes.
@@ -7601,6 +8595,24 @@ safe-outputs:
     # (optional)
     staged: true
 
+    # Internal hidden feature. Optional list of declarative sample payloads that
+    # exercise this safe-output handler. Used by the hidden `gh aw compile
+    # --use-samples` flag to replace the agentic step with a deterministic replay
+    # through the safe-outputs MCP server. Each entry should conform to the
+    # corresponding MCP tool inputSchema; recognized sidecar keys (currently `patch`
+    # for create-pull-request and push-to-pull-request-branch) are stripped before
+    # schema validation and consumed by the replay driver.
+    # (optional)
+    # Accepted formats:
+
+    # Format 1: array
+    samples: []
+      # Array items: object
+
+    # Format 2: object
+    samples:
+      {}
+
   # Format 2: Enable report_incomplete with default configuration
   report-incomplete: null
 
diff --git a/docs/src/content/docs/reference/frontmatter.md b/docs/src/content/docs/reference/frontmatter.md
index aa64f6a1d8e..98d548d8b33 100644
--- a/docs/src/content/docs/reference/frontmatter.md
+++ b/docs/src/content/docs/reference/frontmatter.md
@@ -195,7 +195,7 @@ runs-on-slim: ubuntu-slim            # Defaults to ubuntu-slim (framework jobs o
 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.), accepts the same string, array, or runner-group object forms as `runs-on`, and defaults to `ubuntu-slim`. `safe-outputs.runs-on` takes precedence over `runs-on-slim` for safe-output jobs specifically.
+`runs-on` applies to the main agent job only. `runs-on-slim` applies to all framework/generated jobs (activation, safe-outputs, unlock, etc.), accepts the same string, array, or runner-group object forms as `runs-on`, and defaults to `ubuntu-slim`. `safe-outputs.runs-on` and `safe-outputs.threat-detection.runs-on` also accept the same runner forms and take precedence where applicable.
 
 `timeout-minutes` accepts an integer or a GitHub Actions expression string (e.g. `${{ inputs.timeout }}`), letting a reusable `workflow_call` workflow parameterize its own timeout from caller inputs. It applies to the workflow being compiled, **not** to plain caller jobs that invoke a reusable workflow with job-level `uses:` — GitHub rejects `timeout-minutes` there.
 
diff --git a/docs/src/content/docs/reference/safe-outputs.md b/docs/src/content/docs/reference/safe-outputs.md
index 7ec695aa2bd..90c082c735f 100644
--- a/docs/src/content/docs/reference/safe-outputs.md
+++ b/docs/src/content/docs/reference/safe-outputs.md
@@ -1681,7 +1681,7 @@ Specify a custom runner for safe output jobs (default: `ubuntu-slim`):
 ```aw
 ---
 safe-outputs:
-  runs-on: ubuntu-22.04
+  runs-on: [self-hosted, linux, x64]
   create-issue: {}
 ---
 ```
diff --git a/docs/src/content/docs/reference/self-hosted-runners.md b/docs/src/content/docs/reference/self-hosted-runners.md
index 313647a1351..af58648b0ce 100644
--- a/docs/src/content/docs/reference/self-hosted-runners.md
+++ b/docs/src/content/docs/reference/self-hosted-runners.md
@@ -93,7 +93,7 @@ runs-on: [self-hosted, linux, x64]
 safe-outputs:
   create-issue: {}
   threat-detection:
-    runs-on: ubuntu-latest
+    runs-on: [self-hosted, linux, x64]
 ---
 ```
 
@@ -107,8 +107,9 @@ Framework jobs — activation, pre-activation, safe-outputs, unlock, APM, update
 ---
 on: issues
 runs-on: [self-hosted, linux, x64]
-runs-on-slim: self-hosted
+runs-on-slim: [self-hosted, linux, x64]
 safe-outputs:
+  runs-on: [self-hosted, linux, x64]
   create-issue: {}
 ---
 ```
diff --git a/pkg/parser/schema_location_test.go b/pkg/parser/schema_location_test.go
index 4a67cffb0ad..38af5c5c851 100644
--- a/pkg/parser/schema_location_test.go
+++ b/pkg/parser/schema_location_test.go
@@ -442,6 +442,41 @@ func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_AcceptsRunsOnSlimO
 	}
 }
 
+func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_AcceptsSafeOutputsRunsOnArrayForm(t *testing.T) {
+	frontmatter := map[string]any{
+		"on": "workflow_dispatch",
+		"safe-outputs": map[string]any{
+			"create-issue": map[string]any{},
+			"runs-on":      []any{"self-hosted", "linux", "x64"},
+		},
+	}
+
+	err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(frontmatter, "/test/workflow.md")
+	if err != nil {
+		t.Fatalf("ValidateMainWorkflowFrontmatterWithSchemaAndLocation() unexpected error = %v", err)
+	}
+}
+
+func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_AcceptsThreatDetectionRunsOnObjectForm(t *testing.T) {
+	frontmatter := map[string]any{
+		"on": "workflow_dispatch",
+		"safe-outputs": map[string]any{
+			"create-issue": map[string]any{},
+			"threat-detection": map[string]any{
+				"runs-on": map[string]any{
+					"group":  "arc-custom",
+					"labels": []any{"linux", "x64"},
+				},
+			},
+		},
+	}
+
+	err := ValidateMainWorkflowFrontmatterWithSchemaAndLocation(frontmatter, "/test/workflow.md")
+	if err != nil {
+		t.Fatalf("ValidateMainWorkflowFrontmatterWithSchemaAndLocation() unexpected error = %v", err)
+	}
+}
+
 func TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_AcceptsAllowedBaseBranchesInCreatePullRequest(t *testing.T) {
 	frontmatter := map[string]any{
 		"on": map[string]any{
diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json
index b5040a2d38e..017514c28cc 100644
--- a/pkg/parser/schemas/main_workflow_schema.json
+++ b/pkg/parser/schemas/main_workflow_schema.json
@@ -9848,8 +9848,16 @@
                   "description": "Per-run AI Credits budget for threat-detection engine execution. Accepts numeric values only (expressions are not supported). When unset, gh-aw emits a runtime default expression `${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }}`."
                 },
                 "runs-on": {
-                  "type": "string",
-                  "description": "Runner specification for the detection job. Overrides agent.runs-on for the detection job only. Defaults to agent.runs-on."
+                  "$ref": "#/$defs/github_actions_runs_on",
+                  "description": "Runner specification for the detection job. Overrides agent.runs-on for the detection job only. Supports string, array, or runner-group object forms. Defaults to agent.runs-on.",
+                  "examples": [
+                    "ubuntu-latest",
+                    ["self-hosted", "linux", "x64"],
+                    {
+                      "group": "larger-runners",
+                      "labels": ["ubuntu-latest-8-cores"]
+                    }
+                  ]
                 },
                 "continue-on-error": {
                   "$ref": "#/$defs/templatable_boolean",
@@ -10322,8 +10330,16 @@
           ]
         },
         "runs-on": {
-          "type": "string",
-          "description": "Runner specification for all safe-outputs jobs (activation, create-issue, add-comment, etc.). Single runner label (e.g., 'ubuntu-slim', 'ubuntu-latest', 'windows-latest', 'self-hosted'). Defaults to 'ubuntu-slim'. See https://github.blog/changelog/2025-10-28-1-vcpu-linux-runner-now-available-in-github-actions-in-public-preview/"
+          "$ref": "#/$defs/github_actions_runs_on",
+          "description": "Runner specification for all safe-outputs jobs (activation, create-issue, add-comment, etc.). Supports string, array, or runner-group object forms. Defaults to 'ubuntu-slim'. See https://github.blog/changelog/2025-10-28-1-vcpu-linux-runner-now-available-in-github-actions-in-public-preview/",
+          "examples": [
+            "ubuntu-slim",
+            ["self-hosted", "linux", "x64"],
+            {
+              "group": "larger-runners",
+              "labels": ["ubuntu-latest-8-cores"]
+            }
+          ]
         },
         "steps": {
           "type": "array",
diff --git a/pkg/workflow/central_slash_command_workflow.go b/pkg/workflow/central_slash_command_workflow.go
index 028c95f4ff8..36d93def314 100644
--- a/pkg/workflow/central_slash_command_workflow.go
+++ b/pkg/workflow/central_slash_command_workflow.go
@@ -485,7 +485,7 @@ func resolveCentralSlashRunsOn(workflowDataList []*WorkflowData) string {
 
 		resolved := constants.DefaultActivationJobRunnerImage
 		if wd.SafeOutputs != nil && strings.TrimSpace(wd.SafeOutputs.RunsOn) != "" {
-			resolved = strings.TrimSpace(wd.SafeOutputs.RunsOn)
+			resolved = formatRunsOnSnippetForInlineValue(wd.SafeOutputs.RunsOn)
 		} else if strings.TrimSpace(wd.RunsOnSlim) != "" {
 			resolved = formatRunsOnSnippetForInlineValue(wd.RunsOnSlim)
 		}
diff --git a/pkg/workflow/frontmatter_parsing.go b/pkg/workflow/frontmatter_parsing.go
index ba49622afeb..cb32f6762fe 100644
--- a/pkg/workflow/frontmatter_parsing.go
+++ b/pkg/workflow/frontmatter_parsing.go
@@ -34,6 +34,16 @@ func ParseFrontmatterConfig(frontmatter map[string]any) (*FrontmatterConfig, err
 	if err := validateRunsOnValue(config.RunsOnSlim); err != nil {
 		return nil, err
 	}
+	if safeOutputsRaw, ok := frontmatter["safe-outputs"].(map[string]any); ok {
+		if err := validateRunsOnValue(safeOutputsRaw["runs-on"]); err != nil {
+			return nil, err
+		}
+		if threatRaw, ok := safeOutputsRaw["threat-detection"].(map[string]any); ok {
+			if err := validateRunsOnValue(threatRaw["runs-on"]); err != nil {
+				return nil, err
+			}
+		}
+	}
 
 	// Parse typed Runtimes field if runtimes exist
 	if len(config.Runtimes) > 0 {
diff --git a/pkg/workflow/frontmatter_types_test.go b/pkg/workflow/frontmatter_types_test.go
index efcee762cff..3c65e56eb31 100644
--- a/pkg/workflow/frontmatter_types_test.go
+++ b/pkg/workflow/frontmatter_types_test.go
@@ -397,6 +397,40 @@ func TestParseFrontmatterConfig(t *testing.T) {
 				reconstructed2 := config2.ToMap()
 				assert.Equal(t, reconstructed, reconstructed2)
 			})
+
+			t.Run("handles safe-outputs runs-on forms", func(t *testing.T) {
+				tests := []struct {
+					name           string
+					safeOutputs    any
+					expectedRunsOn string
+				}{
+					{
+						name: "safe-outputs.runs-on string form",
+						safeOutputs: map[string]any{
+							"runs-on": "ubuntu-latest",
+						},
+						expectedRunsOn: "runs-on: ubuntu-latest",
+					},
+					{
+						name: "safe-outputs.runs-on array form",
+						safeOutputs: map[string]any{
+							"runs-on": []any{"self-hosted", "linux"},
+						},
+						expectedRunsOn: "runs-on:\n- self-hosted\n- linux",
+					},
+				}
+
+				for _, tt := range tests {
+					t.Run(tt.name, func(t *testing.T) {
+						config, err := ParseFrontmatterConfig(map[string]any{
+							"safe-outputs": tt.safeOutputs,
+						})
+						require.NoError(t, err)
+						require.NotNil(t, config.SafeOutputs)
+						assert.Equal(t, tt.expectedRunsOn, config.SafeOutputs.RunsOn)
+					})
+				}
+			})
 		}
 	})
 
diff --git a/pkg/workflow/imports.go b/pkg/workflow/imports.go
index 69bc768c46a..dd6de131297 100644
--- a/pkg/workflow/imports.go
+++ b/pkg/workflow/imports.go
@@ -435,7 +435,7 @@ func mergeSafeOutputConfig(result *SafeOutputsConfig, config map[string]any, c *
 	if result.MaximumPatchSize == 0 && importedConfig.MaximumPatchSize > 0 {
 		result.MaximumPatchSize = importedConfig.MaximumPatchSize
 	}
-	if result.RunsOn == "" && importedConfig.RunsOn != "" {
+	if isEmptyRunsOnValue(result.RunsOn) && !isEmptyRunsOnValue(importedConfig.RunsOn) {
 		result.RunsOn = importedConfig.RunsOn
 	}
 	if len(importedConfig.Needs) > 0 {
diff --git a/pkg/workflow/runs_on_snippet.go b/pkg/workflow/runs_on_snippet.go
new file mode 100644
index 00000000000..6a4f2d679d9
--- /dev/null
+++ b/pkg/workflow/runs_on_snippet.go
@@ -0,0 +1,29 @@
+package workflow
+
+import (
+	"strings"
+
+	"github.com/goccy/go-yaml"
+)
+
+// renderRunsOnSnippet serializes a runs-on value into a "runs-on: ..." YAML snippet.
+// Returns empty string for empty/unset values.
+func renderRunsOnSnippet(value any) string {
+	if isEmptyRunsOnValue(value) {
+		return ""
+	}
+
+	var yamlBytes []byte
+	var err error
+	if valueMap, ok := value.(map[string]any); ok {
+		orderedValue := OrderMapFields(valueMap, []string{})
+		yamlBytes, err = yaml.MarshalWithOptions(yaml.MapSlice{{Key: "runs-on", Value: orderedValue}}, DefaultMarshalOptions...)
+	} else {
+		yamlBytes, err = yaml.Marshal(map[string]any{"runs-on": value})
+	}
+	if err != nil {
+		return ""
+	}
+
+	return strings.TrimSuffix(string(yamlBytes), "\n")
+}
diff --git a/pkg/workflow/runs_on_unmarshal.go b/pkg/workflow/runs_on_unmarshal.go
new file mode 100644
index 00000000000..3e981b94a86
--- /dev/null
+++ b/pkg/workflow/runs_on_unmarshal.go
@@ -0,0 +1,42 @@
+package workflow
+
+import "encoding/json"
+
+// UnmarshalJSON supports string/array/object forms for safe-outputs.runs-on while
+// storing a normalized runs-on YAML snippet for downstream rendering.
+func (c *SafeOutputsConfig) UnmarshalJSON(data []byte) error {
+	type alias SafeOutputsConfig
+	aux := &struct {
+		RunsOn any `json:"runs-on,omitempty"`
+		*alias
+	}{
+		alias: (*alias)(c),
+	}
+
+	if err := json.Unmarshal(data, aux); err != nil {
+		return err
+	}
+
+	c.RunsOn = renderRunsOnSnippet(aux.RunsOn)
+	return nil
+}
+
+// UnmarshalJSON supports string/array/object forms for
+// safe-outputs.threat-detection.runs-on while storing a normalized runs-on YAML
+// snippet for downstream rendering.
+func (c *ThreatDetectionConfig) UnmarshalJSON(data []byte) error {
+	type alias ThreatDetectionConfig
+	aux := &struct {
+		RunsOn any `json:"runs-on,omitempty"`
+		*alias
+	}{
+		alias: (*alias)(c),
+	}
+
+	if err := json.Unmarshal(data, aux); err != nil {
+		return err
+	}
+
+	c.RunsOn = renderRunsOnSnippet(aux.RunsOn)
+	return nil
+}
diff --git a/pkg/workflow/runs_on_validation.go b/pkg/workflow/runs_on_validation.go
index 9af09569cf0..f7bf52cb7f8 100644
--- a/pkg/workflow/runs_on_validation.go
+++ b/pkg/workflow/runs_on_validation.go
@@ -39,25 +39,40 @@ const macOSRunnerFAQURL = "https://github.github.com/gh-aw/reference/faq/#why-ar
 //
 // Returns an error with a FAQ link if a macOS runner is detected, nil otherwise.
 func validateRunsOn(frontmatter map[string]any, markdownPath string) error {
-	runsOn, exists := frontmatter["runs-on"]
-	if !exists {
-		return nil
-	}
-
 	runsOnValidationLog.Printf("Validating runs-on configuration")
 
-	labels := extractRunnerLabels(runsOn)
-	for _, label := range labels {
-		lower := strings.ToLower(label)
-		if strings.HasPrefix(lower, "macos-") || strings.EqualFold(lower, "macos") {
-			return formatCompilerError(markdownPath, "error",
-				fmt.Sprintf("runner '%s' is not supported in agentic workflows.\n\n"+
-					"macOS runners are not supported because agentic workflows rely on containers "+
-					"for the secure Agent Workflow Firewall sandbox, and GitHub-hosted macOS runners "+
-					"do not support container jobs.\n\n"+
-					"Use 'ubuntu-latest' (default) or another Linux-based runner instead.\n\n"+
-					"See %s for details.",
-					label, macOSRunnerFAQURL), nil)
+	runsOnFields := []struct {
+		name  string
+		value any
+	}{
+		{name: "runs-on", value: frontmatter["runs-on"]},
+		{name: "runs-on-slim", value: frontmatter["runs-on-slim"]},
+	}
+	if safeOutputs, ok := frontmatter["safe-outputs"].(map[string]any); ok {
+		runsOnFields = append(runsOnFields, struct {
+			name  string
+			value any
+		}{name: "safe-outputs.runs-on", value: safeOutputs["runs-on"]})
+		if threatDetection, ok := safeOutputs["threat-detection"].(map[string]any); ok {
+			runsOnFields = append(runsOnFields, struct {
+				name  string
+				value any
+			}{name: "safe-outputs.threat-detection.runs-on", value: threatDetection["runs-on"]})
+		}
+	}
+
+	for _, field := range runsOnFields {
+		labels := extractRunnerLabels(field.value)
+		for _, label := range labels {
+			lower := strings.ToLower(label)
+			if strings.HasPrefix(lower, "macos-") || strings.EqualFold(lower, "macos") {
+				return formatCompilerError(markdownPath, "error",
+					fmt.Sprintf("%s includes unsupported runner '%s'.\n\n"+
+						"Agentic workflows require Linux containers and container jobs. Use a Linux runner label or runner-group configuration instead.\n\n"+
+						"Example: runs-on: [self-hosted, linux, x64]\n\n"+
+						"See %s for details.",
+						field.name, label, macOSRunnerFAQURL), nil)
+			}
 		}
 	}
 
diff --git a/pkg/workflow/runs_on_validation_test.go b/pkg/workflow/runs_on_validation_test.go
index 00bdc80f79a..622684aac0e 100644
--- a/pkg/workflow/runs_on_validation_test.go
+++ b/pkg/workflow/runs_on_validation_test.go
@@ -119,6 +119,40 @@ func TestValidateRunsOn(t *testing.T) {
 			errorInMsg:  "containers",
 			description: "Error should explain containers requirement",
 		},
+		{
+			name:        "macos in runs-on-slim array",
+			frontmatter: map[string]any{"runs-on-slim": []any{"self-hosted", "macos-14"}},
+			wantErr:     true,
+			errorInMsg:  "runs-on-slim",
+			description: "runs-on-slim array containing macos runner should be rejected",
+		},
+		{
+			name: "macos in safe-outputs.runs-on array",
+			frontmatter: map[string]any{
+				"safe-outputs": map[string]any{
+					"runs-on": []any{"self-hosted", "macos-latest"},
+				},
+			},
+			wantErr:     true,
+			errorInMsg:  "safe-outputs.runs-on",
+			description: "safe-outputs.runs-on array containing macos runner should be rejected",
+		},
+		{
+			name: "macos in safe-outputs.threat-detection.runs-on labels",
+			frontmatter: map[string]any{
+				"safe-outputs": map[string]any{
+					"threat-detection": map[string]any{
+						"runs-on": map[string]any{
+							"group":  "runner-group",
+							"labels": []any{"linux", "macos-latest"},
+						},
+					},
+				},
+			},
+			wantErr:     true,
+			errorInMsg:  "safe-outputs.threat-detection.runs-on",
+			description: "threat-detection runs-on labels containing macos runner should be rejected",
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/pkg/workflow/safe_outputs_config.go b/pkg/workflow/safe_outputs_config.go
index a052ba7148e..7cf4beb7d8b 100644
--- a/pkg/workflow/safe_outputs_config.go
+++ b/pkg/workflow/safe_outputs_config.go
@@ -527,9 +527,7 @@ func (c *Compiler) extractSafeOutputsConfig(frontmatter map[string]any) *SafeOut
 
 			// Handle runs-on configuration
 			if runsOn, exists := outputMap["runs-on"]; exists {
-				if runsOnStr, ok := runsOn.(string); ok {
-					config.RunsOn = runsOnStr
-				}
+				config.RunsOn = renderRunsOnSnippet(runsOn)
 			}
 
 			// Handle timeout-minutes configuration
diff --git a/pkg/workflow/safe_outputs_import_test.go b/pkg/workflow/safe_outputs_import_test.go
index bcb95cac7ca..4e2ae9576a2 100644
--- a/pkg/workflow/safe_outputs_import_test.go
+++ b/pkg/workflow/safe_outputs_import_test.go
@@ -788,7 +788,7 @@ This workflow uses the imported meta configuration.
 	// Note: When main workflow has safe-outputs section, extractSafeOutputsConfig sets MaximumPatchSize default (4096)
 	// before merge happens, so imported value is not used. User should specify max-patch-size in main workflow.
 	assert.Equal(t, 4096, workflowData.SafeOutputs.MaximumPatchSize, "MaximumPatchSize defaults to 4096 when main has safe-outputs")
-	assert.Equal(t, "ubuntu-latest", workflowData.SafeOutputs.RunsOn, "RunsOn should be imported")
+	assert.Equal(t, "runs-on: ubuntu-latest", workflowData.SafeOutputs.RunsOn, "RunsOn should be imported")
 }
 
 // TestSafeOutputsImportMetaFieldsMainTakesPrecedence tests that main workflow meta fields take precedence over imports
@@ -929,7 +929,7 @@ This workflow uses only imported safe-outputs configuration.
 	assert.Equal(t, "${{ secrets.IMPORT_TOKEN }}", workflowData.SafeOutputs.GitHubToken, "GitHubToken should be imported")
 	assert.Equal(t, 4096, workflowData.SafeOutputs.MaximumPatchSize, "MaximumPatchSize should be imported")
 	assert.True(t, workflowData.SafeOutputs.Staged, "Staged should be imported and set to true")
-	assert.Equal(t, "ubuntu-22.04", workflowData.SafeOutputs.RunsOn, "RunsOn should be imported")
+	assert.Equal(t, "runs-on: ubuntu-22.04", workflowData.SafeOutputs.RunsOn, "RunsOn should be imported")
 }
 
 // TestSafeOutputsImportJobsFromSharedWorkflow tests that safe-outputs.jobs can be imported from shared workflows
diff --git a/pkg/workflow/safe_outputs_runs_on_test.go b/pkg/workflow/safe_outputs_runs_on_test.go
index 5c97f98349c..46045bbdfb8 100644
--- a/pkg/workflow/safe_outputs_runs_on_test.go
+++ b/pkg/workflow/safe_outputs_runs_on_test.go
@@ -48,6 +48,38 @@ safe-outputs:
 This is a test workflow.`,
 			expectedRunsOn: "runs-on: windows-latest",
 		},
+		{
+			name: "custom runs-on array",
+			frontmatter: `---
+on: push
+safe-outputs:
+  create-issue:
+    title-prefix: "[ai] "
+  runs-on: [self-hosted, linux, x64]
+---
+
+# Test Workflow
+
+This is a test workflow.`,
+			expectedRunsOn: "runs-on:\n    - self-hosted\n    - linux\n    - x64",
+		},
+		{
+			name: "custom runs-on object",
+			frontmatter: `---
+on: push
+safe-outputs:
+  create-issue:
+    title-prefix: "[ai] "
+  runs-on:
+    group: runner-group
+    labels: [linux, x64]
+---
+
+# Test Workflow
+
+This is a test workflow.`,
+			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n      - linux\n      - x64",
+		},
 	}
 
 	for _, tt := range tests {
@@ -372,14 +404,14 @@ func TestFormatFrameworkJobRunsOn(t *testing.T) {
 			name: "safe-outputs.runs-on takes precedence over runs-on-slim",
 			data: &WorkflowData{
 				RunsOnSlim:  "runs-on: ubuntu-22.04",
-				SafeOutputs: &SafeOutputsConfig{RunsOn: "self-hosted"},
+				SafeOutputs: &SafeOutputsConfig{RunsOn: "runs-on: self-hosted"},
 			},
 			expectedRunsOn: "runs-on: self-hosted",
 		},
 		{
 			name: "safe-outputs.runs-on used when runs-on-slim is empty",
 			data: &WorkflowData{
-				SafeOutputs: &SafeOutputsConfig{RunsOn: "windows-latest"},
+				SafeOutputs: &SafeOutputsConfig{RunsOn: "runs-on: windows-latest"},
 			},
 			expectedRunsOn: "runs-on: windows-latest",
 		},
@@ -391,6 +423,20 @@ func TestFormatFrameworkJobRunsOn(t *testing.T) {
 			},
 			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
 		},
+		{
+			name: "safe-outputs.runs-on array snippet indents continuation lines by 4 spaces",
+			data: &WorkflowData{
+				SafeOutputs: &SafeOutputsConfig{RunsOn: "runs-on:\n- self-hosted\n- linux"},
+			},
+			expectedRunsOn: "runs-on:\n    - self-hosted\n    - linux",
+		},
+		{
+			name: "safe-outputs.runs-on object snippet indents continuation lines by 4 spaces",
+			data: &WorkflowData{
+				SafeOutputs: &SafeOutputsConfig{RunsOn: "runs-on:\n  group: runner-group\n  labels:\n  - linux"},
+			},
+			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n      - linux",
+		},
 		{
 			name: "runs-on-slim array snippet indents continuation lines by 4 spaces",
 			data: &WorkflowData{
diff --git a/pkg/workflow/safe_outputs_runtime.go b/pkg/workflow/safe_outputs_runtime.go
index d28d1120951..753d81b3400 100644
--- a/pkg/workflow/safe_outputs_runtime.go
+++ b/pkg/workflow/safe_outputs_runtime.go
@@ -25,7 +25,7 @@ var safeOutputsRuntimeLog = logger.New("workflow:safe_outputs_runtime")
 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
+		return c.indentYAMLLines(data.SafeOutputs.RunsOn, "    ")
 	}
 	if data != nil && data.RunsOnSlim != "" {
 		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-slim: %s", data.RunsOnSlim)
diff --git a/pkg/workflow/threat_detection.go b/pkg/workflow/threat_detection.go
index 3ae34607623..865a299494b 100644
--- a/pkg/workflow/threat_detection.go
+++ b/pkg/workflow/threat_detection.go
@@ -199,9 +199,7 @@ func (c *Compiler) parseThreatDetectionObjectConfig(configMap map[string]any) *T
 
 	// Parse runs-on field
 	if runOn, exists := configMap["runs-on"]; exists {
-		if runOnStr, ok := runOn.(string); ok {
-			threatConfig.RunsOn = runOnStr
-		}
+		threatConfig.RunsOn = renderRunsOnSnippet(runOn)
 	}
 
 	// Parse continue-on-error field (default: true).
@@ -968,7 +966,7 @@ func (c *Compiler) buildDetectionJob(data *WorkflowData) (*Job, error) {
 	// not need the same custom runner as safe-outputs.
 	runsOn := "runs-on: ubuntu-latest"
 	if data.SafeOutputs.ThreatDetection.RunsOn != "" {
-		runsOn = "runs-on: " + data.SafeOutputs.ThreatDetection.RunsOn
+		runsOn = data.SafeOutputs.ThreatDetection.RunsOn
 	}
 
 	// Detection job condition: always run if agent job was not skipped AND produced outputs or a patch.
diff --git a/pkg/workflow/threat_detection_test.go b/pkg/workflow/threat_detection_test.go
index 105e272ca65..fc7bfbbfbb3 100644
--- a/pkg/workflow/threat_detection_test.go
+++ b/pkg/workflow/threat_detection_test.go
@@ -153,7 +153,32 @@ func TestParseThreatDetectionConfig(t *testing.T) {
 				},
 			},
 			expectedConfig: &ThreatDetectionConfig{
-				RunsOn: "self-hosted",
+				RunsOn: "runs-on: self-hosted",
+			},
+		},
+		{
+			name: "object with runs-on array override",
+			outputMap: map[string]any{
+				"threat-detection": map[string]any{
+					"runs-on": []any{"self-hosted", "linux", "x64"},
+				},
+			},
+			expectedConfig: &ThreatDetectionConfig{
+				RunsOn: "runs-on:\n- self-hosted\n- linux\n- x64",
+			},
+		},
+		{
+			name: "object with runs-on group+labels override",
+			outputMap: map[string]any{
+				"threat-detection": map[string]any{
+					"runs-on": map[string]any{
+						"group":  "runner-group",
+						"labels": []any{"linux", "x64"},
+					},
+				},
+			},
+			expectedConfig: &ThreatDetectionConfig{
+				RunsOn: "runs-on:\n  group: runner-group\n  labels:\n  - linux\n  - x64",
 			},
 		},
 		{

From dbab45388c3d8d0262ac9ca759881d600c1a9ce9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Jun 2026 19:34:42 +0000
Subject: [PATCH 4/5] Harden runs-on snippet normalization and validation
 readability

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/workflow/runs_on_snippet.go      | 11 +++++++++++
 pkg/workflow/runs_on_validation.go   | 16 ++++++----------
 pkg/workflow/safe_outputs_runtime.go |  5 +++--
 pkg/workflow/threat_detection.go     |  2 +-
 4 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/pkg/workflow/runs_on_snippet.go b/pkg/workflow/runs_on_snippet.go
index 6a4f2d679d9..8af4f8f7e0d 100644
--- a/pkg/workflow/runs_on_snippet.go
+++ b/pkg/workflow/runs_on_snippet.go
@@ -27,3 +27,14 @@ func renderRunsOnSnippet(value any) string {
 
 	return strings.TrimSuffix(string(yamlBytes), "\n")
 }
+
+func normalizeRunsOnSnippet(value string) string {
+	value = strings.TrimSpace(value)
+	if value == "" {
+		return ""
+	}
+	if strings.HasPrefix(value, "runs-on:") {
+		return value
+	}
+	return "runs-on: " + value
+}
diff --git a/pkg/workflow/runs_on_validation.go b/pkg/workflow/runs_on_validation.go
index f7bf52cb7f8..ac94445f7e4 100644
--- a/pkg/workflow/runs_on_validation.go
+++ b/pkg/workflow/runs_on_validation.go
@@ -41,23 +41,19 @@ const macOSRunnerFAQURL = "https://github.github.com/gh-aw/reference/faq/#why-ar
 func validateRunsOn(frontmatter map[string]any, markdownPath string) error {
 	runsOnValidationLog.Printf("Validating runs-on configuration")
 
-	runsOnFields := []struct {
+	type runnerField struct {
 		name  string
 		value any
-	}{
+	}
+
+	runsOnFields := []runnerField{
 		{name: "runs-on", value: frontmatter["runs-on"]},
 		{name: "runs-on-slim", value: frontmatter["runs-on-slim"]},
 	}
 	if safeOutputs, ok := frontmatter["safe-outputs"].(map[string]any); ok {
-		runsOnFields = append(runsOnFields, struct {
-			name  string
-			value any
-		}{name: "safe-outputs.runs-on", value: safeOutputs["runs-on"]})
+		runsOnFields = append(runsOnFields, runnerField{name: "safe-outputs.runs-on", value: safeOutputs["runs-on"]})
 		if threatDetection, ok := safeOutputs["threat-detection"].(map[string]any); ok {
-			runsOnFields = append(runsOnFields, struct {
-				name  string
-				value any
-			}{name: "safe-outputs.threat-detection.runs-on", value: threatDetection["runs-on"]})
+			runsOnFields = append(runsOnFields, runnerField{name: "safe-outputs.threat-detection.runs-on", value: threatDetection["runs-on"]})
 		}
 	}
 
diff --git a/pkg/workflow/safe_outputs_runtime.go b/pkg/workflow/safe_outputs_runtime.go
index 753d81b3400..c0bdf8026db 100644
--- a/pkg/workflow/safe_outputs_runtime.go
+++ b/pkg/workflow/safe_outputs_runtime.go
@@ -24,8 +24,9 @@ var safeOutputsRuntimeLog = logger.New("workflow:safe_outputs_runtime")
 //  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 c.indentYAMLLines(data.SafeOutputs.RunsOn, "    ")
+		snippet := normalizeRunsOnSnippet(data.SafeOutputs.RunsOn)
+		safeOutputsRuntimeLog.Printf("Framework job runs-on from safe-outputs: %s", snippet)
+		return c.indentYAMLLines(snippet, "    ")
 	}
 	if data != nil && data.RunsOnSlim != "" {
 		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-slim: %s", data.RunsOnSlim)
diff --git a/pkg/workflow/threat_detection.go b/pkg/workflow/threat_detection.go
index 865a299494b..ef2f9ed9958 100644
--- a/pkg/workflow/threat_detection.go
+++ b/pkg/workflow/threat_detection.go
@@ -966,7 +966,7 @@ func (c *Compiler) buildDetectionJob(data *WorkflowData) (*Job, error) {
 	// not need the same custom runner as safe-outputs.
 	runsOn := "runs-on: ubuntu-latest"
 	if data.SafeOutputs.ThreatDetection.RunsOn != "" {
-		runsOn = data.SafeOutputs.ThreatDetection.RunsOn
+		runsOn = normalizeRunsOnSnippet(data.SafeOutputs.ThreatDetection.RunsOn)
 	}
 
 	// Detection job condition: always run if agent job was not skipped AND produced outputs or a patch.

From 94ed72eb22b02a4ada2d277915d012c477acda9d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Jun 2026 21:36:24 +0000
Subject: [PATCH 5/5] Fix runs-on YAML nesting and correct patch-size defaults
 docs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 .../docs/reference/frontmatter-full.md        |  6 +--
 pkg/workflow/frontmatter_types_test.go        |  2 +-
 pkg/workflow/runs_on_snippet.go               | 40 ++++++++++++++++---
 pkg/workflow/safe_outputs_runs_on_test.go     | 26 ++++++------
 pkg/workflow/safe_outputs_runtime.go          |  5 ++-
 pkg/workflow/threat_detection_test.go         |  4 +-
 6 files changed, 56 insertions(+), 27 deletions(-)

diff --git a/docs/src/content/docs/reference/frontmatter-full.md b/docs/src/content/docs/reference/frontmatter-full.md
index 2b00d013eef..7bff2c00ed5 100644
--- a/docs/src/content/docs/reference/frontmatter-full.md
+++ b/docs/src/content/docs/reference/frontmatter-full.md
@@ -4912,7 +4912,7 @@ safe-outputs:
 
     # Maximum allowed size for git patches in kilobytes (KB) for create-pull-request
     # only. Overrides safe-outputs max-patch-size for this output type. Defaults to
-    # 1024 KB (1 MB) when unset.
+    # 4096 KB (4 MB) when unset.
     # (optional)
     max-patch-size: 1
 
@@ -6925,7 +6925,7 @@ safe-outputs:
 
     # Maximum allowed size for git patches in kilobytes (KB) for
     # push-to-pull-request-branch only. Overrides safe-outputs max-patch-size for this
-    # output type. Defaults to 1024 KB (1 MB) when unset.
+    # output type. Defaults to 4096 KB (4 MB) when unset.
     # (optional)
     max-patch-size: 1
 
@@ -8117,7 +8117,7 @@ safe-outputs:
       # (optional)
       workflows: "read"
 
-  # Maximum allowed size for git patches in kilobytes (KB). Defaults to 1024 KB (1
+  # Maximum allowed size for git patches in kilobytes (KB). Defaults to 4096 KB (4
   # MB). If patch exceeds this size, the job will fail.
   # (optional)
   max-patch-size: 1
diff --git a/pkg/workflow/frontmatter_types_test.go b/pkg/workflow/frontmatter_types_test.go
index 3c65e56eb31..49345fb7f61 100644
--- a/pkg/workflow/frontmatter_types_test.go
+++ b/pkg/workflow/frontmatter_types_test.go
@@ -416,7 +416,7 @@ func TestParseFrontmatterConfig(t *testing.T) {
 						safeOutputs: map[string]any{
 							"runs-on": []any{"self-hosted", "linux"},
 						},
-						expectedRunsOn: "runs-on:\n- self-hosted\n- linux",
+						expectedRunsOn: "runs-on:\n  - self-hosted\n  - linux",
 					},
 				}
 
diff --git a/pkg/workflow/runs_on_snippet.go b/pkg/workflow/runs_on_snippet.go
index 8af4f8f7e0d..a2e17b2b35a 100644
--- a/pkg/workflow/runs_on_snippet.go
+++ b/pkg/workflow/runs_on_snippet.go
@@ -6,6 +6,11 @@ import (
 	"github.com/goccy/go-yaml"
 )
 
+func runsOnMarshalOptions() []yaml.EncodeOption {
+	opts := append([]yaml.EncodeOption{}, DefaultMarshalOptions...)
+	return append(opts, yaml.IndentSequence(true))
+}
+
 // renderRunsOnSnippet serializes a runs-on value into a "runs-on: ..." YAML snippet.
 // Returns empty string for empty/unset values.
 func renderRunsOnSnippet(value any) string {
@@ -17,9 +22,9 @@ func renderRunsOnSnippet(value any) string {
 	var err error
 	if valueMap, ok := value.(map[string]any); ok {
 		orderedValue := OrderMapFields(valueMap, []string{})
-		yamlBytes, err = yaml.MarshalWithOptions(yaml.MapSlice{{Key: "runs-on", Value: orderedValue}}, DefaultMarshalOptions...)
+		yamlBytes, err = yaml.MarshalWithOptions(yaml.MapSlice{{Key: "runs-on", Value: orderedValue}}, runsOnMarshalOptions()...)
 	} else {
-		yamlBytes, err = yaml.Marshal(map[string]any{"runs-on": value})
+		yamlBytes, err = yaml.MarshalWithOptions(map[string]any{"runs-on": value}, runsOnMarshalOptions()...)
 	}
 	if err != nil {
 		return ""
@@ -33,8 +38,33 @@ func normalizeRunsOnSnippet(value string) string {
 	if value == "" {
 		return ""
 	}
-	if strings.HasPrefix(value, "runs-on:") {
-		return value
+
+	snippet := value
+	if !strings.HasPrefix(snippet, "runs-on:") {
+		snippet = "runs-on: " + snippet
+	}
+
+	var snippetMap map[string]any
+	if err := yaml.Unmarshal([]byte(snippet), &snippetMap); err == nil {
+		if runsOnValue, ok := snippetMap["runs-on"]; ok {
+			if rendered := renderRunsOnSnippet(runsOnValue); rendered != "" {
+				return rendered
+			}
+		}
+	}
+	return ensureRunsOnContinuationIndent(snippet)
+}
+
+func ensureRunsOnContinuationIndent(snippet string) string {
+	lines := strings.Split(snippet, "\n")
+	if len(lines) <= 1 {
+		return snippet
+	}
+	for i := 1; i < len(lines); i++ {
+		if strings.TrimSpace(lines[i]) == "" || strings.HasPrefix(lines[i], " ") {
+			continue
+		}
+		lines[i] = "  " + lines[i]
 	}
-	return "runs-on: " + value
+	return strings.Join(lines, "\n")
 }
diff --git a/pkg/workflow/safe_outputs_runs_on_test.go b/pkg/workflow/safe_outputs_runs_on_test.go
index 46045bbdfb8..cd47b518f1e 100644
--- a/pkg/workflow/safe_outputs_runs_on_test.go
+++ b/pkg/workflow/safe_outputs_runs_on_test.go
@@ -61,7 +61,7 @@ safe-outputs:
 # Test Workflow
 
 This is a test workflow.`,
-			expectedRunsOn: "runs-on:\n    - self-hosted\n    - linux\n    - x64",
+			expectedRunsOn: "runs-on:\n      - self-hosted\n      - linux\n      - x64",
 		},
 		{
 			name: "custom runs-on object",
@@ -78,7 +78,7 @@ safe-outputs:
 # Test Workflow
 
 This is a test workflow.`,
-			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n      - linux\n      - x64",
+			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n        - linux\n        - x64",
 		},
 	}
 
@@ -303,7 +303,7 @@ safe-outputs:
 # Test Workflow
 
 This is a test workflow.`,
-			expectedRunsOn:   "runs-on:\n    - self-hosted\n    - ubuntu2404\n    - x64\n    - host",
+			expectedRunsOn:   "runs-on:\n      - self-hosted\n      - ubuntu2404\n      - x64\n      - host",
 			checkJobPatterns: []string{"\n  activation:", "\n  safe_outputs:"},
 		},
 		{
@@ -321,7 +321,7 @@ safe-outputs:
 # Test Workflow
 
 This is a test workflow.`,
-			expectedRunsOn:   "runs-on:\n      group: runner-group\n      labels:\n      - ubuntu2404\n      - x64",
+			expectedRunsOn:   "runs-on:\n      group: runner-group\n      labels:\n        - ubuntu2404\n        - x64",
 			checkJobPatterns: []string{"\n  activation:", "\n  safe_outputs:"},
 		},
 		{
@@ -424,34 +424,32 @@ func TestFormatFrameworkJobRunsOn(t *testing.T) {
 			expectedRunsOn: "runs-on: " + constants.DefaultActivationJobRunnerImage,
 		},
 		{
-			name: "safe-outputs.runs-on array snippet indents continuation lines by 4 spaces",
+			name: "safe-outputs.runs-on array snippet preserves valid YAML nesting",
 			data: &WorkflowData{
 				SafeOutputs: &SafeOutputsConfig{RunsOn: "runs-on:\n- self-hosted\n- linux"},
 			},
-			expectedRunsOn: "runs-on:\n    - self-hosted\n    - linux",
+			expectedRunsOn: "runs-on:\n      - self-hosted\n      - linux",
 		},
 		{
-			name: "safe-outputs.runs-on object snippet indents continuation lines by 4 spaces",
+			name: "safe-outputs.runs-on object snippet preserves valid YAML nesting",
 			data: &WorkflowData{
 				SafeOutputs: &SafeOutputsConfig{RunsOn: "runs-on:\n  group: runner-group\n  labels:\n  - linux"},
 			},
-			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n      - linux",
+			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n        - linux",
 		},
 		{
-			name: "runs-on-slim array snippet indents continuation lines by 4 spaces",
+			name: "runs-on-slim array snippet preserves valid YAML nesting",
 			data: &WorkflowData{
 				RunsOnSlim: "runs-on:\n- self-hosted\n- ubuntu2404",
 			},
-			expectedRunsOn: "runs-on:\n    - self-hosted\n    - ubuntu2404",
+			expectedRunsOn: "runs-on:\n      - self-hosted\n      - ubuntu2404",
 		},
 		{
-			// Object continuation lines start at 2-space (DefaultMarshalOptions) so
-			// indentYAMLLines("    ") produces 2+4=6 spaces for each continuation line.
-			name: "runs-on-slim group+labels object snippet indents continuation lines by 4 spaces",
+			name: "runs-on-slim group+labels object snippet preserves valid YAML nesting",
 			data: &WorkflowData{
 				RunsOnSlim: "runs-on:\n  group: runner-group\n  labels:\n  - ubuntu2404",
 			},
-			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n      - ubuntu2404",
+			expectedRunsOn: "runs-on:\n      group: runner-group\n      labels:\n        - ubuntu2404",
 		},
 	}
 
diff --git a/pkg/workflow/safe_outputs_runtime.go b/pkg/workflow/safe_outputs_runtime.go
index c0bdf8026db..5517a5202c2 100644
--- a/pkg/workflow/safe_outputs_runtime.go
+++ b/pkg/workflow/safe_outputs_runtime.go
@@ -29,8 +29,9 @@ func (c *Compiler) formatFrameworkJobRunsOn(data *WorkflowData) string {
 		return c.indentYAMLLines(snippet, "    ")
 	}
 	if data != nil && data.RunsOnSlim != "" {
-		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-slim: %s", data.RunsOnSlim)
-		return c.indentYAMLLines(data.RunsOnSlim, "    ")
+		snippet := normalizeRunsOnSnippet(data.RunsOnSlim)
+		safeOutputsRuntimeLog.Printf("Framework job runs-on from runs-on-slim: %s", snippet)
+		return c.indentYAMLLines(snippet, "    ")
 	}
 	safeOutputsRuntimeLog.Printf("Framework job runs-on using default: %s", constants.DefaultActivationJobRunnerImage)
 	return "runs-on: " + constants.DefaultActivationJobRunnerImage
diff --git a/pkg/workflow/threat_detection_test.go b/pkg/workflow/threat_detection_test.go
index e69efb8588e..40bc59ce992 100644
--- a/pkg/workflow/threat_detection_test.go
+++ b/pkg/workflow/threat_detection_test.go
@@ -164,7 +164,7 @@ func TestParseThreatDetectionConfig(t *testing.T) {
 				},
 			},
 			expectedConfig: &ThreatDetectionConfig{
-				RunsOn: "runs-on:\n- self-hosted\n- linux\n- x64",
+				RunsOn: "runs-on:\n  - self-hosted\n  - linux\n  - x64",
 			},
 		},
 		{
@@ -178,7 +178,7 @@ func TestParseThreatDetectionConfig(t *testing.T) {
 				},
 			},
 			expectedConfig: &ThreatDetectionConfig{
-				RunsOn: "runs-on:\n  group: runner-group\n  labels:\n  - linux\n  - x64",
+				RunsOn: "runs-on:\n  group: runner-group\n  labels:\n    - linux\n    - x64",
 			},
 		},
 		{
