Problem
The compiler emits a hard error when any inline ${{ ... }} GitHub Actions expression remains inside a run: shell script in the generated lock.yml:
error: compiler regression detected: GitHub Actions expressions found in run: shell scripts of compiled workflow
The compiler must rewrite expressions in run: blocks to env variables.
Use env: assignments and shell variable references instead of inline ${{ ... }} in run: scripts.
There is currently no codemod in gh aw fix that rewrites the source workflow to eliminate this pattern. Users hit a wall: the compiler says "the compiler must rewrite" but the compiler doesn't, and fix has nothing for this case.
Evidence (cross-run signal)
microsoft/aspire → .github/workflows/milestone-changelog.md
- Failed on 2026-05-15 daily run
- Failed again on 2026-05-16 daily run with the same error
- 3 other workflows in the same repo were auto-fixed cleanly; only this pattern is left behind.
The error specifically calls out ${{ github.token }} inside a run: heredoc:
Examples found:
- ${{ github.token }}
in: echo "GH_TOKEN=${{ github.token }}" >> "$GITHUB_OUTPUT"
Proposed codemod: auto-hoist-run-expressions
Scan source .md workflow files for ${{ ... }} expressions inside run: blocks (both literal-scalar | form and inline string form). For each occurrence:
- Generate a stable, deterministic env var name from the expression (e.g.
${{ github.token }} → EXPR_GITHUB_TOKEN, ${{ env.FOO }} → EXPR_FOO, dedup across the step).
- Add the binding under the step's
env: block (create the block if missing).
- Replace the inline
${{ ... }} with $VARNAME (or "$VARNAME" inside double-quoted contexts) inside the run script.
- Preserve original indentation, quoting style, and surrounding text.
Before
- name: Capture token
run: |
echo "GH_TOKEN=${{ github.token }}" >> "$GITHUB_OUTPUT"
After
- name: Capture token
env:
EXPR_GITHUB_TOKEN: ${{ github.token }}
run: |
echo "GH_TOKEN=$EXPR_GITHUB_TOKEN" >> "$GITHUB_OUTPUT"
Why this is high priority (P1)
- It is the only hard compile failure in the top-20 audit two days in a row.
- The compiler's own error message describes the exact rewrite the codemod should perform.
- It closes the loop: users would no longer need to read the error and manually rewrite.
- The compiler safeguards in the meantime (writing to
.invalid.yml) confirm the pattern is well-classified.
Edge cases to handle
- Expressions that resolve to non-string values (numeric, boolean) → keep env binding (Actions always stringifies).
- Expressions inside quoted strings vs. bare context → preserve quoting around the variable reference.
- Multiple occurrences of the same expression in one run block → reuse the same env var.
- Multiple distinct expressions in one step → emit each as its own
EXPR_* binding.
- PowerShell /
shell: pwsh run blocks → use $env:VARNAME syntax instead of $VARNAME.
- Conservative: leave inline expressions used as conditions/non-script contexts (
if:, step args, etc.) alone — they are not affected by the regression check.
References
- Companion: daily compatibility summary issue (2026-05-16)
- §25949808920
Generated by 🔧 Daily AW Cross-Repo Compile Check · ● 13.5M · ◷
Problem
The compiler emits a hard error when any inline
${{ ... }}GitHub Actions expression remains inside arun:shell script in the generated lock.yml:There is currently no codemod in
gh aw fixthat rewrites the source workflow to eliminate this pattern. Users hit a wall: the compiler says "the compiler must rewrite" but the compiler doesn't, andfixhas nothing for this case.Evidence (cross-run signal)
microsoft/aspire→.github/workflows/milestone-changelog.mdThe error specifically calls out
${{ github.token }}inside arun:heredoc:Proposed codemod:
auto-hoist-run-expressionsScan source
.mdworkflow files for${{ ... }}expressions insiderun:blocks (both literal-scalar|form and inline string form). For each occurrence:${{ github.token }}→EXPR_GITHUB_TOKEN,${{ env.FOO }}→EXPR_FOO, dedup across the step).env:block (create the block if missing).${{ ... }}with$VARNAME(or"$VARNAME"inside double-quoted contexts) inside the run script.Before
After
Why this is high priority (P1)
.invalid.yml) confirm the pattern is well-classified.Edge cases to handle
EXPR_*binding.shell: pwshrun blocks → use$env:VARNAMEsyntax instead of$VARNAME.if:, step args, etc.) alone — they are not affected by the regression check.References