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

# Designing Section Output Schemas

> Use outputSchema to govern shape, structure and rendering of generated sections — from free prose to EHR-ready key/value blocks

<Badge className="accent-badge" shape="rounded">Beta</Badge>

<Note>
  Schema design patterns shown here use the new `/documents/sections` and `/documents/templates` API. See [Create a Section](/textgen/section-creation) for the full endpoint mechanics.
</Note>

## Why schema is the headline feature

`outputSchema` on a section does two things at once:

1. **Declares the shape** of what the LLM is allowed to emit — a string, a number, a structured object with named fields, an array of objects, and so on. The model is steered to fit this shape.
2. **Drives the rendering** of that output via format strings (`fieldFormat`, `itemFormat`) so the rendered Markdown/text matches your downstream consumer — an EHR field, a structured pipeline, a free-text note block.

Schema descriptions, enums, patterns, defaults, and min/max constraints are **all** part of the prompt the model sees. Use them as guidance, not just validation.

<Tip>Schema design is iterative. Start narrow (string + a tight `contentPrompt`), then widen the schema as you discover repeatable structure in the outputs.</Tip>

## Node types at a glance

`outputSchema` is one of five node types, discriminated by `type`. The table lists each type and the fields you can set; **bold** fields are required, the rest are optional.

| `type`    | Use when                                 | Required                | Optional                                               |
| :-------- | :--------------------------------------- | :---------------------- | :----------------------------------------------------- |
| `string`  | Free prose, single labels, fixed phrases | **`type`**              | `description`, `default`, `enum`, `pattern`            |
| `number`  | Measurements, counts, scores             | **`type`**              | `description`, `default`, `enum`, `minimum`, `maximum` |
| `boolean` | Yes/no facts (e.g. "fasting?")           | **`type`**              | `description`, `default`                               |
| `array`   | Lists of any node type                   | **`type`**, **`items`** | `description`, `itemFormat`, `minItems`, `maxItems`    |
| `object`  | Structured blocks with named fields      | **`type`**              | `description`, `fields[]`, `fieldFormat`               |

**Important:** the schema for an array's `items` can itself be any node — including another `array` or `object`. That's the lever for everything below.

## Field reference — what each option does

Most fields are technically optional, but `description` is **strongly recommended** on every node — it doubles as a prompt to steer the LLM, not just metadata.

### Common to all node types

| Field         | Purpose                                                                                                                                                                                                                                         |
| :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`        | The discriminator. One of `string`, `number`, `boolean`, `array`, `object`. Always required.                                                                                                                                                    |
| `description` | Prompt text the model sees when generating this part of the output. Optional but strongly recommended — this is your main lever to clarify what *this specific node* should contain, in addition to the section's `instructions.contentPrompt`. |

### String-specific

| Field     | Purpose                                                                                                                                                                                                                                          |
| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `default` | Fallback string if the model has nothing to emit for this node.                                                                                                                                                                                  |
| `enum`    | A closed set of allowed values. The model must pick one of these strings.                                                                                                                                                                        |
| `pattern` | A **regular expression** the output should match. The model is steered toward emitting a string that conforms (e.g. `^\d{2,3}/\d{2,3}$` for a blood-pressure value). Not a hard validator — pair with `enum`/`description` for stricter control. |

### Number-specific

| Field                 | Purpose                                                                |
| :-------------------- | :--------------------------------------------------------------------- |
| `default`             | Fallback numeric value when nothing applies.                           |
| `enum`                | Closed set of allowed numeric values.                                  |
| `minimum` / `maximum` | Plausible range bounds. Acts as a prompt anchor as well as validation. |

### Boolean-specific

| Field     | Purpose                                                     |
| :-------- | :---------------------------------------------------------- |
| `default` | Fallback `true`/`false` when the source material is silent. |

### Array-specific

| Field                   | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `items` *(required)*    | The schema for each element. Can be any node type — `string`, `number`, `object`, even another `array`.                                                                                                                                                                                                                                                                                                                                                                         |
| `itemFormat`            | Per-item rendering. A custom format string that **must contain the `{item}` placeholder** — applied per element. For bullets use `"- {item}\n"`; for prefixed entries use e.g. `"Rp. {item}\n"`. Note: there is no built-in auto-incrementing index token, so a "numbered" rendering (1., 2., 3., …) cannot be produced from `itemFormat` alone — model the section as a `string` and ask the model to emit the numbering in its content, or accept bullets via `"- {item}\n"`. |
| `minItems` / `maxItems` | Bounds on the number of items the model may emit.                                                                                                                                                                                                                                                                                                                                                                                                                               |

### Object-specific

| Field         | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| :------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fields[]`    | The fixed set of fields the object contains. Each entry requires `key`, `description`, and `value` (any node type).                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `fieldFormat` | Single unified format string controlling how the object is rendered. Two modes — pick one per object: **(a) Per-field iteration** with generic `{key}` and `{value}` placeholders (e.g. `"{key}: {value}\n"` for inline subheadings, `"{key}\n{value}\n"` for block subheadings, `"**{key}**: {value}\n"` for bold Markdown). The template is applied to every field. **(b) Custom layout** with specific field-key placeholders that match defined `fields[]` (e.g. `"{test}: {result} ({status})"`). The format string is rendered once with all fields substituted. |

***

## Composing schemas — quick reference

| Pattern                                                                           | Shape                                                               | Use for                                                                                                                                                                                                |
| :-------------------------------------------------------------------------------- | :------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `string`                                                                          | One line of prose                                                   | HPI, Chief Complaint, single-paragraph Assessment                                                                                                                                                      |
| `string` + `enum`                                                                 | One value from a closed set                                         | Triage acuity, urgency, disposition                                                                                                                                                                    |
| `string` + `enum` + keyword rules in `description` (+ `default`)                  | Keyword-driven classification — one value out, nothing else         | Encounter disposition (admit / discharge / transfer / …), tobacco status, pregnancy status, severity class — any EHR picker or analytics dimension where the receiver needs a stable categorical value |
| `number` + `minimum`/`maximum`                                                    | Constrained measure                                                 | Vital values, scores, counts                                                                                                                                                                           |
| `array` of `string` + `itemFormat`                                                | Repeating short items                                               | Diagnoses, Medications, Plan items                                                                                                                                                                     |
| `array` of `object` containing a nested `array` with indented `itemFormat`        | Multi-level lists (e.g. numbered parent + indented bullet children) | Plan items with sub-bullets, treatment steps with instructions, action lists with contingencies                                                                                                        |
| `array` of `object` (free title)                                                  | Dynamic key/value rows                                              | Objective findings, Diagnostic results, Physical Exam                                                                                                                                                  |
| `array` of `object` (enum'd title)                                                | Constrained-key rows                                                | Review of Systems with standardized domains                                                                                                                                                            |
| `object` + `fieldFormat` per-field iteration (`{key}` / `{value}`)                | Fixed-subheading block, optionally with per-field style rules       | Pre-op screening, OT Activity & Participation, pain assessment, fixed-form SOAP-style blocks                                                                                                           |
| `object` + `fieldFormat` custom layout (literal text + `{fieldKey}` placeholders) | Sentence-template scaffold                                          | Referral letter, discharge letter, any note with fixed phrasing around variable content                                                                                                                |
| `object` + `fieldFormat` custom layout with escaped `{{` `}}`                     | Layout with literal braces in output                                | EHR placeholder scaffolds, mixed-type test rows, structured discharge summaries                                                                                                                        |

## Where schema interacts with the rest of the prompt

The model receives, in priority order:

1. **Section `instructions`** — `contentPrompt`, `writingStylePrompt`, `miscPrompt`.
2. **Template-level instructions** — `instructions.prompt` on the parent template (when used in a template).
3. **Schema-level guidance** — every `description`, `enum`, `pattern`, `default`, `minimum`, `maximum`, `minItems`, `maxItems` you supply on the `outputSchema`.

Schema-level guidance is where you encode **per-field rules** that vary inside one section (e.g. "this field is 'Nil' when denied", "this field is one of these abbreviations"). Use `instructions.contentPrompt` for the overall section content/scope; use schema `description`s for field-specific behavior.

## Applying a schema to a Corti Standard section

A common pattern is: keep a Corti Standard section's full prompt machinery (`heading`, `contentPrompt`, `writingStylePrompt`, `miscPrompt`) but swap its `outputSchema` for one of the patterns above — e.g. take the curated `corti-hpi` prompts and emit a structured object for an EHR pipeline.

Two ways to do this:

* **Fork the Standard (persistent).** `POST /documents/sections` with `inheritFromId: <standard-section-uuid>` and only `generation.outputSchema` in the body. Everything else is inherited. See [Corti Standards — override `outputSchema`](/textgen/corti-standards#override-outputschema-structured-output-from-a-standard).
* **Override per call (ephemeral).** Submit the new `outputSchema` inside `templateRef.overrides.sections[].generation.outputSchema` on `POST /documents`. See [Guided Synthesis — Path 2](/textgen/documents-guided-synthesis/path-2-templateref-overrides) and [Customization Cookbook — Recipe 2](/textgen/customization-cookbook/recipe-2-inherit-corti-standard).

In **both** forms, `outputSchema` overrides are **wholesale** — whatever you submit fully replaces the parent's schema; partial schemas are not merged. When the change is structural (e.g. `string` → `object`/`array`), consider overriding `writingStylePrompt` in the same request so the parent's wording rules don't conflict with the new shape.

## Related

<Columns cols={2}>
  <Card title="Create a Section" href="/textgen/section-creation" icon="list-tree">
    Wrap any of these schemas in a full section create request — name, language, instructions, lifecycle.
  </Card>

  <Card title="Corti Standards" href="/textgen/corti-standards" icon="library">
    Browse the curated library — many of the patterns above are how Corti standard sections are built.
  </Card>
</Columns>

***

## Worked clinical examples

The patterns below are pulled from real Corti standard sections — adapted so you can copy/paste them into your own `POST /documents/sections` request, lift specific fields, or reference them as a parent via `inheritFromId`.

Each example shows the **full `outputSchema`** (you'd wrap it in the standard `name`/`language`/`generation.instructions`/`generation.outputSchema` envelope from [Create a Section](/textgen/section-creation)).

***

<AccordionGroup>
  <Accordion title="Example 1 — Fixed subheadings with explicit 'not discussed' vs 'nil' defaults">
    **Goal:** A pre-op screening block that always renders the same fixed subheadings in the same order. When the conversation didn't touch a topic, render `Not discussed`. When the patient explicitly denied something, render `Nil`. Don't let the model invent in-between phrases like "patient denies anything noteworthy."

    **Pattern:** object with `fieldFormat: "{key}\\n{value}\\n"` (per-field iteration), fixed `fields[]`, per-field `default`, and explicit guidance in each field's `description` for the negation rule.

    ```json title="outputSchema — fixed subheadings + explicit defaults" expandable theme={null}
    {
      "type": "object",
      "description": "Pre-operative screening block. Render every subheading; never omit a field.",
      "fieldFormat": "{key}\n{value}\n",
      "fields": [
        {
          "key": "Allergies",
          "description": "Allergies and intolerances and their reaction.",
          "value": {
            "type": "string",
            "default": "Not discussed",
            "description": "If the patient explicitly denied allergies, output exactly: Nil"
          }
        },
        {
          "key": "Current medications",
          "description": "Current active medications.",
          "value": {
            "type": "string",
            "default": "Not discussed",
            "description": "If the patient explicitly denied medications, output exactly: Nil"
          }
        },
        {
          "key": "Fasting status",
          "description": "Whether the patient is fasting and since when.",
          "value": {
            "type": "string",
            "default": "Not discussed",
            "description": "If the patient explicitly denied fasting, output exactly: Nil"
          }
        },
        {
          "key": "Anesthesia history",
          "description": "Any previous anesthesia and complications.",
          "value": {
            "type": "string",
            "default": "Not discussed",
            "description": "If the patient explicitly denied any, output exactly: Nil"
          }
        }
      ]
    }
    ```

    **What you get** (with `fieldFormat: "{key}\n{value}\n"` — per-field iteration):

    ```
    Allergies
    Penicillin — anaphylaxis

    Current medications
    Nil

    Fasting status
    NPO since 22:00 yesterday

    Anesthesia history
    Not discussed
    ```

    <Tip>The `description` on each field's value description carries the negation rule for that field — the model sees both the field-level description(s) and the section-level `instructions.contentPrompt`. Use field descriptions for field-specific guidance.</Tip>
  </Accordion>

  <Accordion title="Example 2a — Dynamic organ-system labels (free)">
    **Goal:** Examination findings where the LLM picks the organ-system label dynamically — only the systems actually examined appear in the output, with a clinically appropriate label for each. No predefined enum.

    **Pattern:** array of objects with a `organ-system` string field (no `enum`) and a `finding` string field, joined via `fieldFormat: "{organ-system}: {finding}"`. The model creates as many entries as needed.

    ```json title="outputSchema — dynamic-key array-of-objects" expandable theme={null}
    {
      "type": "array",
      "description": "Open-ended set of examination findings. One entry per body region or system, generated only when relevant findings exist.",
      "items": {
        "type": "object",
        "fields": [
          {
            "key": "organ-system",
            "description": "Body-region or system label, e.g. 'Abdomen', 'Right knee', 'Neuro', 'Cardiovascular'. Choose the most clinically appropriate label for the findings in this entry.",
            "value": { "type": "string" }
          },
          {
            "key": "finding",
            "description": "Concise objective finding text for that label.",
            "value": { "type": "string" }
          }
        ],
        "fieldFormat": "{organ-system}: {finding}"
      },
      "itemFormat": "{item}\n"
    }
    ```

    **What you get:**

    ```
    Abdomen: Soft, non-tender, no palpable masses.
    Neuro: GCS 15. Cranial nerves intact.
    MSK: ROM preserved in all joints; no swelling or deformity.
    ```
  </Accordion>

  <Accordion title="Example 2b — Constrained organ-system labels (enum)">
    **Goal:** Same shape, but every label must come from a fixed clinical abbreviation set you've standardized on for an EHR field.

    **Pattern:** identical to 2a, but the `organ-system` field's string node carries an `enum` of allowed values.

    ```json title="outputSchema — enum-constrained dynamic keys" expandable theme={null}
    {
      "type": "array",
      "description": "Review of systems entries. One entry per domain mentioned. Use only the standardized domain abbreviations.",
      "items": {
        "type": "object",
        "fields": [
          {
            "key": "organ-system",
            "description": "Standardized review-of-systems domain label.",
            "value": {
              "type": "string",
              "enum": ["C-P", "GI", "Resp.", "Neuro", "MSK", "ENT", "GU", "Derm", "HEENT", "Endo", "Psych", "Heme", "Immune"]
            }
          },
          {
            "key": "finding",
            "description": "Symptoms and explicitly denied symptoms for that domain, stated concisely in clinical language.",
            "value": { "type": "string" }
          }
        ],
        "fieldFormat": "{organ-system}: {finding}"
      },
      "itemFormat": "{item}\n"
    }
    ```

    **What you get:**

    ```
    C-P: Denies chest pain or palpitations.
    Resp.: Mild dry cough for 3 days; no shortness of breath.
    GI: Intermittent nausea; no vomiting or diarrhea.
    Neuro: Headache for 3 days; no focal deficits.
    ```

    <Note>
      **When to use which.** Use free titles (2a) when the legal label set is open-ended and clinicians need to choose precise body regions. Use enum (2b) when the downstream consumer (EHR field, analytics pipeline) requires a finite, stable set of labels.
    </Note>
  </Accordion>

  <Accordion title="Example 3 — Structured test results with measures and free-text findings">
    **Goal:** Lab and imaging results where each entry mixes **typed measures** (numeric values with ranges and units), a **status field** drawn from a fixed clinical vocabulary, and a **free-text finding** narrative.

    **Pattern:** array of objects with a `result` string that the model formats consistently (number + unit, or status placeholder for non-numeric studies), plus a typed `status` enum and a free-text `findings` field. Numeric typing is preserved per-test through the `description` instructions; the rendered line stays clean regardless of test type.

    ```json title="outputSchema — mixed-type test results" expandable theme={null}
    {
      "type": "array",
      "description": "Diagnostic test results discussed in the encounter. One entry per test or imaging study.",
      "items": {
        "type": "object",
        "fields": [
          {
            "key": "test",
            "description": "The name of the test, panel, study or modality (e.g. 'Hemoglobin', 'Chest X-ray', 'Troponin I').",
            "value": { "type": "string" }
          },
          {
            "key": "result",
            "description": "For quantitative tests: numeric value with unit, as stated in the source (e.g. '11.8 g/dL', '0.04 ng/mL'). Do not convert units. For non-quantitative studies (imaging, cultures): use a short placeholder such as 'see findings' or 'pending'. Always non-empty.",
            "value": { "type": "string" }
          },
          {
            "key": "status",
            "description": "Interpretation as stated in the source.",
            "value": {
              "type": "string",
              "enum": ["normal", "low", "high", "abnormal", "pending", "not reported"]
            }
          },
          {
            "key": "findings",
            "description": "Free-text findings, qualifiers, or narrative description from the source. Empty string if the quantitative result alone is sufficient.",
            "value": { "type": "string", "default": "" }
          }
        ],
        "fieldFormat": "{test}: {result} ({status}). {findings}"
      },
      "itemFormat": "{item}\n"
    }
    ```

    **What you get:**

    ```
    Hemoglobin: 11.8 g/dL (low). Mildly reduced; no overt anemia.
    Chest X-ray: see findings (normal). No acute infiltrate or effusion.
    Troponin I: 0.04 ng/mL (normal). Within reference range at 0h and 3h.
    ```

    Every row renders cleanly: `result` is always non-empty, so there's no double-space gap, and the rendered line works for quantitative labs and imaging studies alike.

    <Tip>
      **Why not separate `value` and `unit` numeric fields?** It's tempting to model labs as `{ value: number, unit: string }` for strong typing, but `fieldFormat` is a static template — when a field's value is empty or missing, the literal text around it (spaces, parentheses, separators) still renders. An X-ray entry that legitimately has no numeric value would render as `Chest X-ray:  (normal).` — note the double space — because the format template `{test}: {value} {unit} ({status}). {findings}` substitutes empty strings for `value` and `unit`.

      Collapsing measurement into a single string `result` field that the model is instructed to format consistently sidesteps this. If you need strict numeric typing for a downstream pipeline (e.g. lab values into analytics), consider:

      * **Splitting into two sections** — `quantitative-labs` (array of `{ test, value: number, unit, status }`) and `imaging-studies` (array of `{ study, status, findings }`). Each gets a clean, type-appropriate `fieldFormat`.
      * **Post-processing the rendered string** client-side to collapse runs of whitespace.
      * **Keeping the `result` string for human-readable rendering and adding a parallel typed field** that downstream consumers read, e.g. `numericValue: number`. The `numericValue` field can be omitted from the `fieldFormat` rendering entirely and only consumed via `document.structuredDocument` (see [Guided Synthesis — response shape](/textgen/documents-guided-synthesis#response-shape)).
    </Tip>
  </Accordion>

  <Accordion title="Example 4 — Prefixes and standard phrasings via `itemFormat`">
    **Goal:** A prescription section where every line is prefixed with `Rp.`, and a separate dictation block where every utterance begins with a standard "Pt reports:" header.

    **Pattern:** custom `itemFormat` on the array. The `{item}` placeholder is the rendered item; everything else around it is literal text.

    ```json title="outputSchema — prescriptions with Rp. prefix" expandable theme={null}
    {
      "type": "array",
      "description": "Prescriptions issued at this visit. One prescription per entry.",
      "items": {
        "type": "string",
        "description": "Prescription line: drug + strength + form, route, frequency, duration."
      },
      "itemFormat": "Rp. {item}"
    }
    ```

    **What you get:**

    ```
    Rp. Amoxicillin 500 mg PO three times daily for 7 days
    Rp. Ibuprofen 400 mg PO every 6 hours as needed for pain
    ```

    ```json title="outputSchema — dictation with fixed prefix per item" theme={null}
    {
      "type": "array",
      "description": "Patient-reported statements. One quote or paraphrase per entry.",
      "items": { "type": "string" },
      "itemFormat": "Pt reports: {item}"
    }
    ```

    The same `{key}`/`{value}` levers exist on objects via `fieldFormat` (e.g. `"**{key}**: {value}"`) for Markdown-bold headings, or `"## {key}\n{value}"` for full Markdown headings.
  </Accordion>

  <Accordion title="Example 5 — EHR placeholders that survive verbatim">
    **Goal:** A plan section that emits literal placeholder strings — like `{treatment_shared_motherhood_ivf}` — for an EHR system to substitute downstream. The LLM must **not** generate or paraphrase these; they're scaffolding for the EHR, not content.

    **Pattern:** bake the placeholders directly into `fieldFormat` as **literal text**, escaping the curly braces. `fieldFormat` parses `{fieldKey}` as a variable substitution; doubled `{{` and `}}` are escapes that render as a single literal `{` and `}` in the output. Any clinician-authored content goes into a normal field that *is* substituted.

    <Note>
      **Format-string brace escaping.** In `fieldFormat`:

      * A **single** `{fieldKey}` substitutes the value of that field.
      * A **doubled** `{{` renders as a literal `{` in the output; `}}` renders as a literal `}`.

      So to emit literal `{treatment_var}` in the output (single braces around a placeholder name), write `{{treatment_var}}` in the format string — that's `{{` (literal `{`) + `treatment_var` (literal text, no substitution because there's no matching field) + `}}` (literal `}`).

      To emit literal `{<value-of-field_1>}` (literal braces around a substituted value), write `{{{field_1}}}` — that's `{{` + `{field_1}` + `}}`.

      To emit double-brace placeholders like `{{treatment_var}}` literally (Mustache/Handlebars style), each output brace needs its own escape: write `{{{{treatment_var}}}}` in the format string.
    </Note>

    ```json title="outputSchema — EHR placeholders via escaped literal braces" expandable theme={null}
    {
      "type": "object",
      "description": "IVF plan block. Clinician narrative goes into {plan_notes}; the remaining lines are EHR placeholders that survive verbatim for downstream substitution.",
      "fieldFormat": "{plan_notes}\n\nShared Motherhood IVF: {{treatment_shared_motherhood_ivf}}\nWith or without PGT-A (if IVF): {{treatment_pgt_a}}\nNumber of embryos to transfer (if IVF/FET): {{treatment_number_of_embryos}}",
      "fields": [
        {
          "key": "plan_notes",
          "description": "Clinician-authored plan narrative for this visit. May be multi-line; do not include the structured EHR placeholder lines — those are emitted separately.",
          "value": { "type": "string", "default": "" }
        }
      ]
    }
    ```

    **What you get:**

    ```
    Continue stim protocol. Recheck E2 and follicle count in 48h. Consider OPU end of next week.

    Shared Motherhood IVF: {treatment_shared_motherhood_ivf}
    With or without PGT-A (if IVF): {treatment_pgt_a}
    Number of embryos to transfer (if IVF/FET): {treatment_number_of_embryos}
    ```

    The clinician-generated plan text fills `{plan_notes}`; the EHR placeholders pass through as literal text because their braces are escaped. No extra fields and no `enum` tricks needed.

    <Tip>If your EHR expects **double-brace** placeholders (`{{var}}` literal in the output, e.g. Mustache/Handlebars conventions), each delimiter needs its own escape. The format string fragment for that line becomes `{{{{treatment_shared_motherhood_ivf}}}}` — four braces on each side. Verbose but valid.</Tip>
  </Accordion>

  <Accordion title="Example 6 — Different writing styles per subheader via field `description`">
    **Goal:** Inside one section, each subheader (field) follows a **different writing style** — telegraphic for one, flowing prose for another, comma-separated short phrases for a third — without splitting into multiple sections.

    **Pattern:** the section's `instructions.writingStylePrompt` sets the global default; each field's `description` carries the **local style rule** for that subheader. The model reads both and applies the field-level rule where the two disagree.

    ```json title="outputSchema — per-field writing styles" expandable theme={null}
    {
      "type": "object",
      "description": "Pain assessment block. Each subheader has its own writing style.",
      "fieldFormat": "{key}\n{value}\n",
      "fields": [
        {
          "key": "Onset & duration",
          "description": "Telegraphic; no narrative. Anchor with explicit dates or durations (e.g. '3 weeks ago, intermittent').",
          "value": { "type": "string" }
        },
        {
          "key": "Pattern of pain",
          "description": "Flowing prose, one or two sentences. Describe the qualitative character (sharp, dull, throbbing, radiating).",
          "value": { "type": "string" }
        },
        {
          "key": "Aggravating / relieving",
          "description": "Comma-separated short phrases, no full sentences (e.g. 'worse with stairs, eased by ibuprofen').",
          "value": { "type": "string" }
        },
        {
          "key": "Treatments tried",
          "description": "Chronological list, one intervention per line, with outcome appended (e.g. 'Ibuprofen 400 mg TID for 1 week — partial relief').",
          "value": { "type": "string" }
        }
      ]
    }
    ```

    **What you get:**

    ```
    Onset & duration
    3 weeks ago, intermittent.

    Pattern of pain
    Throbbing pain in the lower back, occasionally radiating to the right leg. Worse in the morning, eases over the course of the day.

    Aggravating / relieving
    Worse with stairs, eased by ibuprofen, worse after prolonged sitting.

    Treatments tried
    Paracetamol 500 mg PRN — limited effect
    Ibuprofen 400 mg TID for 1 week — partial relief
    Physiotherapy, 4 sessions — ongoing
    ```

    <Note>**When per-field `description` is enough vs. when to split into multiple sections.** Use this pattern when the styles are contrasts *within* a coherent section that always renders as one block (e.g. a pain assessment). When the subheaders are large enough to be reused independently across templates — or have meaningfully different `contentPrompt` rules — it's cleaner to promote each into its own section in the template instead.</Note>
  </Accordion>

  <Accordion title="Example 7 — OT Activity & Participation (ICF-style fixed subcategories)">
    **Goal:** An occupational therapy block with **fixed ICF-aligned subcategories** — *Self-care, Mobility, Communication, Domestic life, Interpersonal interactions* — each producing free text. Subcategories always render in the same order; subcategories not covered in the source still appear with an explicit "Not assessed" placeholder so downstream consumers can rely on the structure.

    **Pattern:** `object` + `fieldFormat: "{key}\\n{value}\\n"` (per-field iteration) + fixed `fields[]` with a per-field `default` of `"Not assessed"`. This is the OT-clinic equivalent of the pre-op screening pattern in Example 1.

    ```json title="outputSchema — OT Activity & Participation block" expandable theme={null}
    {
      "type": "object",
      "description": "Occupational therapy: Activity & Participation block (ICF-aligned). One free-text observation per fixed subcategory.",
      "fieldFormat": "{key}\n{value}\n",
      "fields": [
        {
          "key": "Self-care",
          "description": "Performance in washing, dressing, toileting, eating, medication management. Note both independent activities and where assistance is needed.",
          "value": { "type": "string", "default": "Not assessed" }
        },
        {
          "key": "Mobility",
          "description": "Walking distance, transfers, stairs, use of mobility aids. Include assistance level.",
          "value": { "type": "string", "default": "Not assessed" }
        },
        {
          "key": "Communication",
          "description": "Receptive and expressive communication, comprehension of instructions, any use of alternative communication.",
          "value": { "type": "string", "default": "Not assessed" }
        },
        {
          "key": "Domestic life",
          "description": "Meal preparation, household tasks, shopping, money management. Note level of independence.",
          "value": { "type": "string", "default": "Not assessed" }
        },
        {
          "key": "Interpersonal interactions",
          "description": "Engagement with family, caregivers and social network. Note changes since onset.",
          "value": { "type": "string", "default": "Not assessed" }
        }
      ]
    }
    ```

    **What you get:**

    ```
    Self-care
    Independent in washing and dressing; requires verbal cueing for medication intake.

    Mobility
    Walks 50 m with a walker; needs assistance for stairs. Transfers independently bed-to-chair.

    Communication
    Receptive language intact; mild word-finding difficulty in expressive speech.

    Domestic life
    Not assessed

    Interpersonal interactions
    Lives with spouse; reports reduced social engagement since onset.
    ```

    The "Domestic life" subheader still renders even though the source material didn't cover it — because the field's `default` is `"Not assessed"`. Downstream consumers see a stable structure across encounters.
  </Accordion>

  <Accordion title="Example 8 — Standard phrases combined with LLM-generated content">
    **Goal:** Output a clinical letter (or any structured note) where **standard sentence templates** wrap **model-generated content**. The connective tissue — salutations, framing sentences, closing — is verbatim; only the clinical content varies between encounters.

    **Pattern:** `object` + `fieldFormat` with full sentences containing `{field}` placeholders. The fixed phrases are just literal text in the format string; each `{field}` is substituted with model-generated content from `fields[]`.

    ```json title="outputSchema — standard phrasing scaffold" expandable theme={null}
    {
      "type": "object",
      "description": "Referral letter scaffold. Fixed phrasing wraps model-generated clinical content.",
      "fieldFormat": "Dear colleague,\n\nThank you for seeing this patient. {chief_complaint}\n\nThe relevant history is as follows: {hpi}\n\nOn examination: {exam_findings}\n\nMy clinical impression is {assessment}. I have started {initiated_treatment}.\n\nI would appreciate your further evaluation and management. Please do not hesitate to contact me with any questions.\n\nKind regards,",
      "fields": [
        {
          "key": "chief_complaint",
          "description": "One sentence stating the reason for referral.",
          "value": { "type": "string" }
        },
        {
          "key": "hpi",
          "description": "Concise history of present illness as flowing prose, 2-4 sentences.",
          "value": { "type": "string" }
        },
        {
          "key": "exam_findings",
          "description": "Key positive findings and pertinent negatives, telegraphic.",
          "value": { "type": "string" }
        },
        {
          "key": "assessment",
          "description": "Provisional diagnosis or working impression, one sentence.",
          "value": { "type": "string" }
        },
        {
          "key": "initiated_treatment",
          "description": "What you have already started (medication, investigation, lifestyle advice). If none, the default phrasing is used.",
          "value": { "type": "string", "default": "no treatment to date" }
        }
      ]
    }
    ```

    **What you get:**

    ```
    Dear colleague,

    Thank you for seeing this patient. The patient presents with a 6-week history of progressive exertional dyspnea.

    The relevant history is as follows: 64-year-old former smoker with known hypertension. Symptoms worsening over the last two weeks with bilateral ankle swelling and orthopnea.

    On examination: BP 148/92, HR 88 regular, bibasal crackles, pitting oedema to mid-shin bilaterally.

    My clinical impression is decompensated heart failure with preserved ejection fraction. I have started furosemide 40 mg PO daily.

    I would appreciate your further evaluation and management. Please do not hesitate to contact me with any questions.

    Kind regards,
    ```

    <Tip>**Compare with Example 5.** In Example 5 the `{{var}}` text is *literal* in the output — the model never touches it. In Example 8, every `{field}` is *substituted* — the literal text is just the connective sentences between the substitutions. Same `fieldFormat` mechanism, opposite intent for the placeholders.</Tip>
  </Accordion>

  <Accordion title="Example 9 — Bullet points nested inside a numbered list">
    **Goal:** A Plan section where each plan item carries a top-level marker (bullet by default — see the numbering caveat below) and 0 or more **indented sub-bullets** with dosing, follow-up timing, contingencies or anything else worth itemising under that step.

    **Pattern:** outer `array` with a custom `itemFormat` containing the `{item}` placeholder. Each item is an `object` with a `summary` string field plus a nested `details` array whose own `itemFormat` includes a **leading indent + bullet marker** (e.g. `"  - {item}\n"`). Compose summary + details via `fieldFormat`. The outer array applies its `itemFormat` once per top-level entry; the inner array's `itemFormat` controls the indented bullet rendering.

    ```json title="outputSchema — plan with nested bullet details" expandable theme={null}
    {
      "type": "array",
      "description": "Plan items, each optionally followed by indented sub-bullets with details.",
      "itemFormat": "* {item}\n",
      "items": {
        "type": "object",
        "fieldFormat": "{summary}\n{details}",
        "fields": [
          {
            "key": "summary",
            "description": "One-line summary of the plan item. Do not prefix with a bullet — the outer itemFormat applies the marker.",
            "value": { "type": "string" }
          },
          {
            "key": "details",
            "description": "Sub-bullets with instructions, dosing notes, follow-up timing or contingencies relevant to this plan item. Omit if the summary is self-contained.",
            "value": {
              "type": "array",
              "description": "Zero or more sub-points under the plan item.",
              "itemFormat": "  - {item}\n",
              "items": { "type": "string" }
            }
          }
        ]
      }
    }
    ```

    **What you get:**

    ```
    * Start corticosteroid cream BID
      - Apply thin layer to affected area
      - Continue for 2 weeks, then taper to once daily
    * Order CBC and CMP
      - Draw before next visit
      - Patient to fast 8h prior
    * Schedule follow-up in 4 weeks
    * Educate patient on warning symptoms
      - Worsening rash or new lesions
      - Fever or systemic symptoms
      - Allergic reaction to topical (rare)
    ```

    **How it works:**

    * The outer `array.itemFormat: "* {item}\n"` puts an asterisk (or any literal marker you choose — `-`, `•`, `1.`) in front of each top-level item.
    * The inner `array.itemFormat: "  - {item}\n"` is the key lever: the **two leading spaces** indent each bullet under its parent, and `-` is the bullet marker. Adjust spacing for deeper nesting (e.g. `"    * {item}\n"` for a four-space-indented sub-sub-list).
    * The object's `fieldFormat: "{summary}\n{details}"` concatenates the summary line with the sub-bullets directly underneath, preserving the visual nesting.
    * If a plan item has no sub-bullets, the `details` array renders as empty and the entry collapses to just the summary line (item 3 above).

    <Warning>
      **Auto-incrementing numbered lists (1., 2., 3., …) cannot be produced via `itemFormat` alone.** The format string is applied per item with no built-in counter — every item would get the same literal prefix (e.g. `"1. {item}"` would render `"1."` in front of every entry).

      If you need true sequential numbering, change the outer shape to a single `string` and instruct the model to emit the numbering itself:

      ```json theme={null}
      {
        "type": "string",
        "description": "Numbered plan with indented sub-bullets. Format each plan item as a numbered line ('1.', '2.', '3.', ...) followed by zero or more indented '- ' sub-bullets two spaces deep."
      }
      ```

      The trade-off: you lose the typed array shape (and the `details.structuredDocument` you'd get from `array of object`). Keep the array shape if you can live with bullets, switch to `string` + prompt if the numbering is mandatory.
    </Warning>

    <Tip>The same indented-bullet trick scales further within the array shape. To get a third level (outer marker → bullet → sub-bullet), nest another `array` inside `details.items` whose own `itemFormat` uses more leading spaces — e.g. `"    · {item}\n"`. The model handles arbitrary nesting; readability for the human reader is usually the constraint.</Tip>
  </Accordion>

  <Accordion title="Example 10 — Diagnoses with indented detail bullets">
    **Goal:** A Diagnoses (problem list) section where each diagnosis is rendered with a top-level marker and an optional ICD/SNOMED code, and each diagnosis carries **indented sub-bullets** describing the clinical findings, reasoning, status, and management pertaining to it. Same structural pattern as Example 9; the field descriptions and the kind of content the LLM is steered toward are diagnosis-focused.

    **Pattern:** outer `array` with a custom `itemFormat` (e.g. `"* {item}\n"`), inner items are `object`s with a `diagnosis` summary string and a nested `details` array. The `details.itemFormat` uses the leading-indent + bullet marker trick to render each sub-point indented under its diagnosis.

    ```json title="outputSchema — diagnoses with indented details" expandable theme={null}
    {
      "type": "array",
      "description": "Problem list of diagnoses discussed in the encounter, ordered with diagnoses related to the current visit first. Each diagnosis is followed by indented sub-bullets for findings, reasoning, status, and management.",
      "itemFormat": "* {item}\n",
      "items": {
        "type": "object",
        "fieldFormat": "{diagnosis}\n{details}",
        "fields": [
          {
            "key": "diagnosis",
            "description": "Diagnosis label as stated in the source material. Include an explicitly mentioned ICD-10 or SNOMED code in parentheses after the name when available (e.g. 'Type 2 diabetes mellitus (E11.9)'). Do not prefix with a marker — the outer itemFormat applies one.",
            "value": { "type": "string" }
          },
          {
            "key": "details",
            "description": "Sub-bullets pertaining to this specific diagnosis. Typical entries: relevant clinical findings or evidence, reasoning, current status (acute, chronic, resolving, stable), and management or plan. One bullet per distinct point; omit categories not supported by the source material.",
            "value": {
              "type": "array",
              "description": "Zero or more sub-points pertaining to the diagnosis.",
              "itemFormat": "  - {item}\n",
              "items": { "type": "string" }
            }
          }
        ]
      }
    }
    ```

    **What you get:**

    ```
    * Eczema, atopic dermatitis (L20.9)
      - Acute flare on bilateral forearms; itchy, no oozing or secondary infection
      - Likely triggered by recent change in laundry detergent (patient history)
      - Plan: topical corticosteroid + trigger avoidance, taper after 2 weeks
    * Seasonal allergic rhinitis
      - Mild symptoms during spring pollen season
      - Currently controlled on PRN second-generation antihistamine
      - No escalation needed
    * Type 2 diabetes mellitus (E11.9)
      - Established; on metformin 1000 mg PO BID
      - Last HbA1c 6.8% (3 months ago); target met
      - Continue current management; recheck HbA1c in 3 months
    * Hypertension, essential (I10)
      - BP today 132/84 mmHg; trending stable on current regimen
    ```

    **How it differs from Example 9:**

    * Structurally **identical** schema shape (outer array + object item with `summary` + nested `details` array). The pattern is reusable.
    * The **field descriptions are diagnosis-specific**: `diagnosis` prompts for label + optional code; `details` prompts for findings, reasoning, status, management.
    * Same graceful-collapse behavior — if a diagnosis only has a name (and the source material doesn't support sub-bullets), the entry renders as just the diagnosis line (item 4 above).

    <Tip>Pair this schema with a `writingStylePrompt` like *"Bullet text is telegraphic; one clinical point per bullet. Do not repeat the diagnosis name inside the bullets."* to keep the indented bullets tight and avoid the model restating the diagnosis label on every line.</Tip>

    <Note>**Need auto-numbered diagnoses (1., 2., 3., …)?** Same caveat as Example 9: `itemFormat` has no built-in counter, so use `string` + a contentPrompt that instructs the model to emit numbered lines with two-space-indented sub-bullets. Trade-off: you lose the typed array-of-objects shape and any `structuredDocument` benefits.</Note>
  </Accordion>

  <Accordion title="Example 11 — Keyword-driven classification (single enum value out)">
    **Goal:** The section emits **exactly one value from a closed list** based on cues in the source material. No free text, no explanation — just the categorical value. Useful for EHR picker fields, analytics dashboards, routing logic, or any downstream consumer that needs a stable enum value rather than narrative content.

    **Pattern:** `string` + `enum` (closed value set) + a rich `description` that teaches the model the **keyword-to-value mapping**. Add `default` for the "no signal in the source" case so the field always renders something deterministic.

    ```json title="outputSchema — encounter disposition classifier" expandable theme={null}
    {
      "type": "string",
      "description": "Classify the patient's encounter disposition based on the clinician's decisions during the visit. Output exactly one of the enum values — no explanation, no surrounding text. Use these keyword cues from the source material:\n\n- 'admit', 'admission', 'inpatient', 'observation unit', 'staying overnight' → 'admit'\n- 'discharge home', 'send home', 'follow up outpatient', 'home with instructions' → 'discharge'\n- 'transfer to', 'higher level of care', 'tertiary center', 'transferring out' → 'transfer'\n- 'consult', 'specialist referral', 'awaiting specialist' → 'consult-pending'\n- 'against medical advice', 'AMA', 'left without being seen' → 'left-ama'\n\nIf the source material doesn't explicitly state a disposition decision, output the default value.",
      "enum": ["admit", "discharge", "transfer", "consult-pending", "left-ama", "undetermined"],
      "default": "undetermined"
    }
    ```

    **What you get** (for a transcript where the clinician says *"…let's send her home with the antibiotic course and a follow-up in two weeks"*):

    ```
    discharge
    ```

    Just the bare enum value, nothing else. Downstream consumers can map it to a UI dropdown selection, an EHR field, a routing decision, or a metric label without any parsing.

    **How it works:**

    * **`enum` is the hard constraint.** The model can only emit one of the listed values — `"admit"`, `"discharge"`, `"transfer"`, `"consult-pending"`, `"left-ama"`, or `"undetermined"`. Free text never leaks through.
    * **`description` is where the classification logic lives.** Spell out which input keywords or phrases map to each enum value. The model reads this alongside the section's `instructions.contentPrompt` when picking the output.
    * **`default` covers the empty-state case** — if the source material has nothing to support a disposition decision, the field renders `"undetermined"` deterministically. (Without a default, the model might still pick a value or return an empty string. With it, your downstream consumer always sees a known value.)

    <Tip>Pair this schema with a tight `writingStylePrompt` like *"Output the enum value only. No quotation marks, no surrounding sentences, no explanations."* if you notice the model occasionally adding narration. The schema alone usually suffices, but the extra instruction is cheap insurance for a strict categorical output.</Tip>

    <Note>**Other clinical use cases that fit this pattern:** triage acuity (ESI levels 1–5), pain severity (mild / moderate / severe), tobacco status (never / former / current), pregnancy status, fall-risk class, cancer stage, AMS level, NYHA functional class, audit/consent yes-no-unknown checks. Each one is a `string` + `enum` + descriptive keyword rules. For numeric scoring (Apgar, GCS, pain 0–10), use `number` + `minimum`/`maximum` instead — see Example 3 patterns.</Note>
  </Accordion>
</AccordionGroup>
