Summary
Prompt templates loaded via prompt: !file ... are rendered as Jinja2 templates, but loader-dependent Jinja constructs such as {% include %}, {% import %}, and {% extends %} cannot work in normal CLI usage.
The renderer creates the Jinja environment with loader=BaseLoader() and renders file-backed prompts via env.from_string(...). Because the YAML !file constructor inlines the file contents into the prompt string, the original template file path/directory is not available at render time, and there is no user-facing way to provide a Jinja search path.
This makes it impossible to factor prompt templates into reusable partials.
Minimal Reproduction
Using Conductor 0.1.20, Jinja2 3.1.6, Python 3.12.
Example files:
workflow.yaml
prompts/main.md.jinja
prompts/_shared.md.jinja
workflow.yaml:
version: "1"
tasks:
example:
prompt: !file prompts/main.md.jinja
prompts/main.md.jinja:
Before include.
{% include "_shared.md.jinja" %}
After include.
prompts/_shared.md.jinja:
Run the workflow with the normal Conductor CLI.
Expected Behavior
The prompt should render successfully and include the contents of _shared.md.jinja, either relative to the prompt file directory or via a documented template search path.
Actual Behavior
Rendering fails with a wrapped template error similar to:
Template rendering failed: _shared.md.jinja
The underlying Jinja error is jinja2.exceptions.TemplateNotFound.
Root Cause
In src/conductor/executor/template.py, TemplateRenderer.__init__ creates the environment with a hard-coded BaseLoader:
self.env = _DictSafeEnvironment(
loader=BaseLoader(),
undefined=StrictUndefined,
autoescape=False,
keep_trailing_newline=True,
)
TemplateRenderer.render() then compiles prompt text using self.env.from_string(template).
Jinja's BaseLoader cannot resolve template names for {% include %}, {% import %}, or {% extends %}. Those constructs require a real loader such as FileSystemLoader, PackageLoader, or a custom loader.
Separately, src/conductor/config/loader.py implements the !file YAML constructor by reading the referenced file and inlining its raw contents into the schema field. That means the prompt's source path/directory is discarded before rendering, so the renderer has no template origin from which to resolve relative includes.
Suggested Direction
Possible fixes:
- Preserve source metadata for
!file prompt values so the renderer knows the prompt file directory.
- Configure a Jinja loader for file-backed prompt templates, such as a
FileSystemLoader rooted at the prompt directory, workflow directory, or an explicitly configured template search path.
- Document the resolution rules for
{% include %}, {% import %}, and {% extends %} in prompt templates.
- If loader-dependent Jinja features are intentionally unsupported, fail earlier with a clearer error message and document that limitation.
Workaround
The only practical workaround I found is to manually inline shared prompt text into each prompt file instead of using Jinja includes.
Environment
- Conductor:
0.1.20
- Jinja2:
3.1.6
- Python:
3.12
Summary
Prompt templates loaded via
prompt: !file ...are rendered as Jinja2 templates, but loader-dependent Jinja constructs such as{% include %},{% import %}, and{% extends %}cannot work in normal CLI usage.The renderer creates the Jinja environment with
loader=BaseLoader()and renders file-backed prompts viaenv.from_string(...). Because the YAML!fileconstructor inlines the file contents into the prompt string, the original template file path/directory is not available at render time, and there is no user-facing way to provide a Jinja search path.This makes it impossible to factor prompt templates into reusable partials.
Minimal Reproduction
Using Conductor
0.1.20, Jinja23.1.6, Python3.12.Example files:
workflow.yaml:prompts/main.md.jinja:prompts/_shared.md.jinja:Run the workflow with the normal Conductor CLI.
Expected Behavior
The prompt should render successfully and include the contents of
_shared.md.jinja, either relative to the prompt file directory or via a documented template search path.Actual Behavior
Rendering fails with a wrapped template error similar to:
The underlying Jinja error is
jinja2.exceptions.TemplateNotFound.Root Cause
In
src/conductor/executor/template.py,TemplateRenderer.__init__creates the environment with a hard-codedBaseLoader:TemplateRenderer.render()then compiles prompt text usingself.env.from_string(template).Jinja's
BaseLoadercannot resolve template names for{% include %},{% import %}, or{% extends %}. Those constructs require a real loader such asFileSystemLoader,PackageLoader, or a custom loader.Separately,
src/conductor/config/loader.pyimplements the!fileYAML constructor by reading the referenced file and inlining its raw contents into the schema field. That means the prompt's source path/directory is discarded before rendering, so the renderer has no template origin from which to resolve relative includes.Suggested Direction
Possible fixes:
!fileprompt values so the renderer knows the prompt file directory.FileSystemLoaderrooted at the prompt directory, workflow directory, or an explicitly configured template search path.{% include %},{% import %}, and{% extends %}in prompt templates.Workaround
The only practical workaround I found is to manually inline shared prompt text into each prompt file instead of using Jinja includes.
Environment
0.1.203.1.63.12