-
Notifications
You must be signed in to change notification settings - Fork 327
Ask: Runtime Parameterization of Compile-Time Frontmatter Fields #23724
Description
As a preamble, I want to stress this is not an issue and more of a discussion of an idea to understand the feasibility of. Tell me to go crawl back into my hole if need be ;)
Problem
We're building reusable workflow_call workflows so teams can uses: a single definition and customize behavior via inputs. Today, some frontmatter fields accept ${{ inputs.xxx }} expressions and some don't — the ones that don't force us to duplicate workflows instead of parameterizing them.
Fields that work: engine.model, runtimes.*.version, env, prompt body
Fields that don't: engine.id, engine.version, tools, network.allowed, timeout-minutes (and likely others we haven't hit yet — MCP server configs, tool allowlists, etc.)
The highest-impact blocker is engine.id. Because the compiler resolves it against a catalog at compile time, a reusable workflow is locked to one engine. Supporting all four engines means maintaining four copies of each workflow, which defeats the purpose.
What We Understand
We looked at the code and understand why these fields are compile-time today:
engine.idselects a Go interface implementation (ClaudeEngine,CopilotEngine, etc.) that emits structurally different installation, execution, MCP config, and log-parsing steps. This isn't just an enum check — it shapes the output YAML. Deferring it would require an architectural change (universal runner, runtime dispatch action, compile-time matrix, etc.).engine.versionis interpolated directly into shell arguments, so accepting expressions is a legitimate injection risk.tools,network.allowed,timeout-minutesare blocked by JSON Schema type constraints (expects array/integer, gets string). The Go extraction code also does strict type assertions. These seem more tractable — the schema and extraction could accept expression strings alongside their current types.
The Ask
Is there appetite to support expression pass-through for frontmatter fields, and if so, what's the preferred approach?
Two levels:
-
Type-constrained fields (
tools,network.allowed,timeout-minutes, MCP configs, and similar): Could the schema and extraction logic accept${{ }}strings as an alternative type and pass them through to the compiled YAML? This would be a targeted change per field. -
engine.id: We understand this is a deeper architectural question. Is there a path being considered (universal runner, runtime shim action, matrix compilation, etc.) that would let callers select the engine at call time? We're happy to contribute or test if there's an approach the team favors.
We're not asking for unchecked pass-through of all expressions everywhere — we understand the security implications (shell injection via engine.version, schema validation protecting against malformed configs). The goal is a principled mechanism for fields where the expression resolves to a valid value at runtime.
Impact
Without this, every axis of variation requires a separate workflow file. Engine × tool-config × network-policy combinations scale multiplicatively. A parameterization path — even partial — would collapse this back to single reusable definitions.