Actio

Out of scope

High-demand GitHub Actions asks a compile-time transpiler structurally can't solve — and why.

Why document non-goals?

Four waves of community research (community discussions, actions/runner issues, Reddit/SO, competitor authoring, and github/customer-feedback enterprise intake) surfaced a recurring set of high-demand GitHub Actions asks that a compile-time transpiler structurally cannot solve. Actio is a build-time compiler with no runtime: it can't touch the platform or see values that only exist while a run is executing.

This page is a reference so we (and contributors) stop re-litigating these, can answer "why doesn't Actio just…", and have honest talking points. Each item below is grouped by the structural root cause, with a representative high-demand issue linked.

Rule of thumb

If the answer depends on a value that exists only at runtime, or on how GitHub stores/scopes/renders something, Actio can't synthesize it. If it's authoring ergonomics over a compile-time-known value, it's in scope.

1. Runtime graph mutation

The job graph is fixed when the workflow is parsed. You can't add/remove/reorder jobs or edges based on values computed during the run.

Why not: these mutate the DAG from runtime state. Actio only knows the DAG at compile time. (Compile-time-known fan-out IS in scope — see edge cases.)

2. Platform security / secrets / identity

Secret storage, scoping, environments, branch protection, and marketplace trust live in the GitHub platform, not in YAML.

Why not: no amount of generated YAML changes where GitHub keeps secrets or enforces protection.

3. UI / run-experience rendering

How runs, jobs, and the Actions tab render is platform UI. YAML can't restyle it.

Why not: runtime-if skipping and tab rendering are UI behaviors. (Compile-time-known skips ARE in scope via static-if — see edge cases.)

4. Runtime expression / context availability

Some contexts and fields just aren't populated where users want them, at runtime.

Why not: when the value is runtime-input-driven, Actio can't inline it. (When the value is compile-time-known, {{ params }} already inlines it into runs-on:/with:/if: where ${{ env }} is rejected — see edge cases.)

5. Concurrency / scheduling semantics

The scheduler decides queueing, cancellation, and conclusions at runtime.

Why not: these are runtime scheduler behaviors. Generated YAML can't change how the queue/conclusion engine works.

6. Native-now — explicit non-goals (don't build)

GitHub shipped these (or close enough). Building macros for them would be redundant churn.

  • actions/runner#409 — ternary / conditional operator → now native (${{ ... && ... || ... }}, and a real conditional landing). Don't add expr-ternary sugar.
  • actions/runner#1182: YAML anchors shipped (changelog, 2025-09-18). Actio now flattens a - *alias whose anchor is a step list into the surrounding steps, so native _anchors: + - *alias cover same-file, no-param step reuse. That makes fragments redundant for that case, so it is deprecated (still compiles, warning only). What anchors still can't do: take typed params or cross files. Those stay with templates: + inject ... with and cross-file inject: ./lib#name. Merge keys remain unshipped upstream (request #185877); Actio accepts the 1.1 merge key (<<:) in source and erases it on emit, with an opt-in strict lint for pure-1.2.2 source.

Edge cases — the compile-time subset IS in scope

The line isn't the topic, it's when the value is known. Where a runtime limitation has a compile-time-known slice, Actio already (or should) cover it:

  • Skipping jobs → runtime UI hide = platform; compile-time-known drop = static-if
  • env in disallowed fields → runtime ${{ env }} = platform; compile-time literal = {{ params }} interpolation ✅
  • Per-leg matrix needs → runtime fromJSON matrix = platform; compile-time-known matrix = expand_matrix: (#97)
  • Typed/validated inputs → runtime coercion = platform; compile-time typing = params

If a future ask lands on the compile-time side of one of these lines, it's a candidate — file it. Everything above stays out of scope by design.

On this page