> ## Documentation Index
> Fetch the complete documentation index at: https://docs.brainworkup.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Reuse one prompt across every patient with Jinja templating

> Use the Luria PROMPTS reference and Jinja2 placeholders to write each agent prompt once, then fill in patient and domain context at runtime.

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.

<Warning>
  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.
</Warning>

## 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](/concepts/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.

```jinja2 theme={null}
Patient {{patient_first_name}}, age {{patient_age}}, presented with {{chief_complaint}}.
```

With the runtime context:

```python theme={null}
context = {
    "patient_first_name": "Sarah",
    "patient_age": 14,
    "chief_complaint": "difficulty concentrating at school",
}
```

The rendered prompt becomes:

```text theme={null}
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.

```jinja2 theme={null}
{% 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.

```jinja2 theme={null}
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.

```python theme={null}
# 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.

```python theme={null}
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

1. 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.
2. Use `{{variable}}` placeholders for anything that varies per patient or per run.
3. Document any non-standard variables in the **Input** field so the calling agent knows what context to pass.
4. 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.
