Skip to content

Compiler emits {{#runtime-import}} but skips the step that resolves it, silently delivering an empty prompt #49102

Description

@FDevTakima

Summary

generateInterpolationAndTemplateStep skips emitting the "Interpolate variables and render templates" step when a workflow has no expressions, no {{#if pattern, no GitHub tool and no inline sub-agents — but the compiler always emits the {{#runtime-import <workflow>.md}} macro for the workflow body.

interpolate_prompt.cjs is the only consumer of that macro. When the step is skipped, the macro reaches the agent verbatim and the entire workflow body is never delivered. The agent receives only the <system> preamble and a literal {{#runtime-import ...}} line.

Compilation reports 0 error(s), 0 warning(s) and validate_prompt_placeholders.sh reports ✅ Placeholder validation complete, so nothing surfaces the failure.

Root cause

pkg/workflow/template.go:

hasExpressions := len(expressionMappings) > 0
hasTemplatePattern := strings.Contains(data.MarkdownContent, "{{#if ")
hasGitHubContext := hasGitHubTool(data.ParsedTools)
hasInlineSubAgents := inlineSubAgentPattern.MatchString(data.MarkdownContent)
hasTemplates := hasTemplatePattern || hasGitHubContext || hasInlineSubAgents

if !hasExpressions && !hasTemplates {
    templateLog.Print("No interpolation or template rendering needed, skipping step generation")
    return
}

The condition never checks for the presence of {{#runtime-import}} macros, even though unified_prompt_step.go documents the dependency explicitly:

// Runtime-import macros are plain text lines processed by the
// interpolate-prompt step; they can live in the same heredoc block
// as surrounding content.

Reproduction

Minimal frontmatter that triggers it — the key is github: false (no GitHub tool ⇒ hasGitHubContext == false) plus a body containing no {{#if and no ${{ }}:

engine:
  id: claude
tools:
  edit:
  github: false
safe-outputs:
  create-pull-request:

Compile, then inspect the generated lock:

$ grep -c interpolate_prompt .github/workflows/<name>.lock.yml
0
$ grep -c runtime-import .github/workflows/<name>.lock.yml
1

At runtime, the activation job's "Print prompt" step shows the unresolved macro:

</system>
{{#runtime-import .github/workflows/<name>.md}}

The activation artifact declares three prompt files but only produces one — the two written by interpolate_prompt.cjs are missing:

/tmp/gh-aw/aw-prompts/prompt.txt                 ← present (still the template)
/tmp/gh-aw/aw-prompts/prompt-template.txt        ← never created
/tmp/gh-aw/aw-prompts/prompt-import-tree.json    ← never created

if-no-files-found: ignore on the upload keeps this silent.

Observed impact

Across four production runs the agent received no instructions at all. Its first action was consistently an attempt to locate its own prompt.
Sometimes the agent doesn't find it so it ends abruptly.

Expected behaviour

Emit the interpolation step whenever the prompt contains runtime-import macros. Something like:

hasRuntimeImports := strings.Contains(data.MarkdownContent, "{{#runtime-import")
hasTemplates := hasTemplatePattern || hasGitHubContext || hasInlineSubAgents || hasRuntimeImports

Note the compiler emits the body's self-import independently of MarkdownContent, so checking the generated prompt chunks rather than the markdown source may be more robust.

A secondary guard would help regardless: validate_prompt_placeholders.sh currently passes a prompt containing an unresolved {{#runtime-import}}. Failing there would turn a silent no-op into a clear build error.

Workaround

Adding any {{#if ...}} block to the workflow body forces hasTemplatePattern to true and restores the step.

Environment

  • gh aw v0.83.4
  • engine: claude (@anthropic-ai/claude-code@2.1.214)
  • self-hosted Linux x64 runner, awf v0.27.37
  • trigger: repository_dispatch

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions