Skip to main content
I built Luria so a single set of prompts could carry me through every evaluation I run — pediatric or adult, one session or three. Jinja2 templating is how I make that possible. Instead of editing patient names and chief complaints into a prompt every time, you write each prompt in agents/prompts/PROMPTS.md once with {{variable}} placeholders. At runtime, you fill them in from a patient context dictionary. This guide walks through how the templating system works, which variables are standardized across all prompts, and how to wire the rendered prompts into your agent pipeline.
Templating only changes how prompts are assembled. The clinical instructions — tone, methodology, output rules — stay hardcoded in PROMPTS.md. You are parameterizing the patient-specific content, not the clinical reasoning.

When to use templates

Use a {{variable}} when the value changes between patients, domains, or visits: Hardcode anything that should stay identical across every evaluation:

Three pieces of syntax

You only need three Jinja2 constructs to template every prompt in Luria.

1. Variable substitution

Rendered with {"patient_first_name": "Sarah", "patient_age": 14, "chief_complaint": "difficulty concentrating"}, this becomes:

2. Conditional blocks

Use {% if %} / {% else %} / {% endif %} for content that only applies to some patients:

3. Loops

Use {% for %} / {% endfor %} to render a list whose length you do not know in advance — recommendations, history items, validity concerns:

Standard variables

These variables are loaded from config.patient.yml and available to every prompt. Use them consistently so a single context dictionary works across the whole pipeline.

Domain-specific variables

These apply only to domain-level prompts such as DOMAIN_INTERPRETATION and SIRF_SYNTHESIS. Pass them per call, not from the global patient config.
Use snake_case for every variable name. Jinja2 substitution is case-sensitive — {{patient_first_name}} and {{patientFirstName}} are not the same variable.

Templated example: NSE_COD_SUMMARY

This is what a real prompt section in PROMPTS.md looks like after templating. Note how the clinical role and methodology remain hardcoded while patient identifiers and history fields use placeholders.

Rendering a prompt from Python

Install jinja2 in your Luria environment (it is already a dependency of the agent pipeline). Then load PROMPTS.md as a template and render it against a context dictionary.

Rendering a single prompt section

If you only need one section — say, NSE_COD_SUMMARY — extract it first with a regex, then render the snippet directly with jinja2.Template:

A reusable helper for the agent pipeline

In practice, every agent in the pipeline ends up calling the same render step. Wrap it in a helper so each agent only needs to pass its context:
Then in the agent:

Common mistakes

Printing a string that contains {{patient_name}} does not substitute anything. You must construct a Template (or load it through an Environment) and call .render(context) for substitution to happen.
Jinja2 silently renders missing variables as an empty string. The prompt still runs, but you get sentences like "Patient Sarah is years old". Validate your context dictionary against the variables used in each prompt before sending it to a model.
A template that reads {{patientName}} will not be filled by a context with key patient_name. Pick snake_case and stick with it everywhere — in config.patient.yml, in PROMPTS.md, and in your Python code.

Workflow recommendation

  1. Add {{variable}} placeholders to PROMPTS.md in agents/prompts/, starting with patient identifiers and chief complaint.
  2. Build a context dictionary from config.patient.yml once per evaluation.
  3. For each agent in the pipeline, pass that context (plus any domain-specific keys) into the render helper.
  4. Send the rendered prompt to the model. Patient data never lives in PROMPTS.md itself, which keeps the prompt library reusable and PHI-free.
For deeper integration patterns and per-prompt variable maps, see agents/prompts/PROMPTS_JINJA_INTEGRATION.md in the Luria source tree.
Last modified on June 3, 2026