Every prompt the Luria pipeline runs — intake admin checklists, NSE summarization, per-domain interpretation, SIRF synthesis — lives in a single canonical reference. Each prompt is templated with Jinja2, so the same prompt text works for every patient. You fill in the placeholders at runtime from config.patient.yml and per-domain context.
This guide covers what the prompt system is, when to use it, and how to extend it.
Templated prompts make patient data substitution mechanical, but they do not
remove your clinical responsibility. Review every agent output before it lands
in a final report.
What the prompts system is
The prompts system has three pieces that work together:
| Piece | Role |
|---|
agents/prompts/PROMPTS.md | Canonical reference for every prompt, organized by pipeline phase |
| Jinja2 placeholders | {{variable}} syntax that adapts each prompt to the current patient |
fill_prompt() runtime helper | Renders a named prompt against a context dictionary |
The reference is the single source of truth. If a prompt is not in PROMPTS.md, it is not part of the pipeline.
When to use templated prompts
Reach for the prompts system when you need to:
- Run the same prompt across many patients without rewriting the prose each time
- Add an optional clause (for example, a parent rater block) that only fires when a flag is set
- Loop over a variable-length list (domain scores, evaluation dates, validity flags)
- Keep clinic-specific identity (clinician name, clinic name, ROI defaults) in one config file
If you are writing a one-off prompt for a single patient, skip the template layer and write it inline. The system is built for repeated runs.
Where prompts live in the pipeline
The reference is organized by the same phases described in the agent pipeline.
| Phase | Prompt name | Used by |
|---|
| A | NSE_ADMIN | nse_admin intake check |
| A | NSE_STT | nse_stt_transcript |
| A | NSE_COD_SUMMARY | nse_cod_summary |
| A | NSE_REPORT | nse_report |
| B | DOMAIN_INTERPRETATION | every domain_text run |
| C | SIRF_SYNTHESIS | sirf_summary |
| C | SIRF_RECOMMENDATIONS | sirf_recs |
| D | REPORT_TYPST | report_assemble |
The three Jinja2 patterns you actually need
You do not need to learn the full Jinja2 language. Three patterns cover every Luria prompt.
1. Variable substitution
Wrap any variable name in double curly braces.
Patient {{patient_first_name}}, age {{patient_age}}, presented with {{chief_complaint}}.
With the runtime context:
context = {
"patient_first_name": "Sarah",
"patient_age": 14,
"chief_complaint": "difficulty concentrating at school",
}
The rendered prompt becomes:
Patient Sarah, age 14, presented with difficulty concentrating at school.
2. Conditional blocks
Use {% if %} to include a block only when a flag is set.
{% if has_parent_rater %}
Parent and patient ratings aligned on {{domain_name}} strengths.
{% else %}
Patient self-report on {{domain_name}} unavailable; rely on clinician observation.
{% endif %}
This is how the domain interpretation prompts conditionally pull in parent or teacher rater language without producing dead clauses when those raters are missing.
3. For loops
Use {% for %} to iterate over lists — multiple evaluation dates, a panel of validity flags, or a set of domain scores.
Evaluation occurred over the following dates:
{% for date in evaluation_dates %}
- {{date}}
{% endfor %}
Standard context variables
The runtime always passes a baseline set of variables loaded from config.patient.yml. You can use any of these in any prompt.
# Patient identity
patient_first_name: str # "Sarah"
patient_last_name: str # "Chen"
patient_full_name: str # "Sarah Chen"
patient_age: int # 14
patient_dob: str # "2010-05-15"
patient_pronouns: str # "she/her"
he_she: str # "she"
his_her: str # "her"
# Evaluation context
evaluation_date: str # "2025-01-15"
evaluation_dates: list[str] # ["2025-01-15", "2025-01-22"]
referral_source: str # "PCP Dr. Smith"
chief_complaint: str # "difficulty concentrating"
# Clinician identity
clinician_name: str # "Joey Trampush, Ph.D."
clinic_name: str # "Brainworkup Neuropsychology, LLC"
Phase B and C prompts receive additional per-domain variables (domain_name, domain_scores, has_parent_rater, validity_concerns) that are passed in by the calling agent.
Rendering a prompt at runtime
Call fill_prompt() with the name of the prompt from PROMPTS.md and the context dictionary.
from luria.prompts import fill_prompt
context = {
"patient_first_name": "Sarah",
"patient_age": 14,
"chief_complaint": "difficulty concentrating",
"domain_name": "Memory",
"has_parent_rater": True,
}
rendered = fill_prompt("DOMAIN_INTERPRETATION", context)
# Pass `rendered` to your model client of choice.
The helper looks up the named section in PROMPTS.md, renders it against the context, and returns the final string ready to send to a model.
Adding a new prompt
- Add a new section to
agents/prompts/PROMPTS.md with the required fields: Role, Worker, Task, Input, Output, and the prompt body in a fenced block.
- Use
{{variable}} placeholders for anything that varies per patient or per run.
- Document any non-standard variables in the Input field so the calling agent knows what context to pass.
- Reference the new prompt from the calling agent by name — never inline the prompt text in code.
Keeping the prompts in one file means you can audit, diff, and version every change to the clinical reasoning the pipeline performs.