Skip to main content
Beta ← Back to Prompting & outputSchema Cookbook

What description is for

outputSchema is mostly typed constraints — type, enum, pattern, minimum/maximum, minItems/maxItems — but every node also accepts a free-form description. That’s your second prompting surface, after instructions. It runs lower in the prompt hierarchy but is uniquely per-node: each description only steers the field or item it’s attached to. Use description when guidance is scoped to one slot in the output and would be wasteful (or confusing) if you put it in section-wide prompts.
For the full reference on schema node types, enum/pattern/itemFormat/fieldFormat, and worked clinical examples, see Section Schemas. This recipe focuses only on what to write inside description.

Where description lives

Every node in an outputSchema accepts a description. The most common places:
  • Top-level node — the whole section’s output. Often a one-sentence summary of what this section produces; sometimes carries structural directives.
  • items (on an array) — describes one entry in the array. Repeated guidance per item.
  • Per-field (on object.fields[]) — the targeted slot. This is the most useful place.
  • Nested field’s value node — for typed leaves that need their own per-field guidance.

Three jobs description does well

1. Scope guidance per field

When an object has many fields, a one-line description per field tells the model exactly what belongs in that slot — with precision and clarity inside the schema. From corti-objective:
"fields": [
  { "key": "General",
    "description": "General condition and overall clinical impression, e.g. level of consciousness, general/nutritional/care status, pain, mobility.",
    "value": { "type": "string" } },
  { "key": "Head & Neck",
    "description": "Findings on examination of the head and neck, e.g. skull, eyes, nose, teeth, tongue, pharynx/tonsils, ears, thyroid, jugular veins.",
    "value": { "type": "string" } },
  { "key": "Heart",
    "description": "Cardiac auscultation: heart sounds, rhythm, murmurs.",
    "value": { "type": "string" } }
]
Each field gets its own scope. contentPrompt stays high-level (“Include direct findings from the physical examination …”); the schema descriptions carve up the body-region anatomy.

2. Layered guidance per schema node

Let’s take the desired output format for a Past Medical History section, e.g.
2015: Appendectomy (acute)
2021: COVID (mild symptoms)
Typically, you would prompt for this in a couple paragraphs. And while you can opt to do so, we recommend you take advantage of the schema for increased robustness and the ability to utilize structured outputs. From corti-past-medical-history:
"outputSchema": {
      "type": "array",
      "description": "Past medical or surgical conditions, one condition per line. Each item is a short clinical note; when a time reference is known, the item begins with the time reference followed by a colon and the condition.",
      "itemFormat": "{item}\n",
      "items": {
        "type": "object",
        "description": "One past medical history entry, with an optional time prefix and the condition or event.",
        "fieldFormat": "{prefix}{content}",
        "fields": [
          {
            "key": "prefix",
            "description": "Time prefix with trailing colon and space, e.g. '2019: ' or 'Age 14: '. Empty string when no time reference is documented in the source.",
            "value": {
              "type": "string"
            }
          },
          {
            "key": "content",
            "description": "The condition, procedure, diagnosis, or event description.",
            "value": {
              "type": "string"
            }
          }
        ]
      }
    }
Each description in the hierarchy steers exactly one layer of the output:
  • array.description — the section-wide goal: a list of past conditions, one per line, with optional time prefixes. The model reads this once to understand the section’s overall job.
  • items.description (the object node) — what one entry in the list represents: a past medical history entry composed of an optional time prefix and a condition. This is the anatomy of a single item — every item the model produces is shaped by this guidance.
  • prefix.description — the targeted rule for just the time-prefix slot: format with trailing colon and space; empty string when no time reference is documented. The model never has to remember this rule while reasoning about the condition itself.
  • content.description — the targeted rule for just the condition slot: the actual diagnosis, procedure, or event description.
fieldFormat: "{prefix}{content}" then literally renders the two filled slots into the per-item string. Why this is more robust than one big paragraph prompt:
  • Each rule is local. The model isn’t asked to remember the prefix-formatting rule while extracting the diagnosis. Each description sits next to the field it governs, so the relevant guidance is always in the model’s immediate context for that slot.
  • The output renders itself. fieldFormat does the literal layout — once the model fills the slots correctly, the colon-and-space, the line breaks, the ordering are guaranteed. You’re not relying on the model to remember formatting rules at generation time.
  • You get structured output. The response is an array of {prefix, content} objects, not a free-text blob. Downstream systems can parse, validate, sort, or post-process each entry — no fragile regex needed to recover structure that was lost when the model rendered the prose.
  • Typed constraints compose for free. Add enum to prefix.value for a closed vocabulary of time formats, minItems/maxItems on the array, pattern for a strict prefix regex — each lives next to the description it qualifies and gets enforced, not just steered.
One free-form paragraph prompt has to carry every one of those rules at once, and there’s no guarantee the model honours all of them in every output. The schema localises each rule and enforces the format programmatically.

3. Per-field fallback conditionals

From corti-allergies:
{ "key": "reaction",
  "description": "Reaction detail with a leading ': ', e.g. ': rash' or ': anaphylaxis'. For a documented allergen with no described reaction, use ': not specified'. Leave empty for no known allergies (NKDA).",
  "value": { "type": "string" } }
Three different fallback states (reaction known / allergen but no reaction / NKDA) — all encoded as one field-scoped description as conditional defaults are not supported.

4. Explain how to use enum options

enum enforces what’s allowed; description explains when to pick which value. From corti-mental-status-exam:
{ "key": "stdLabel",
  "description": "Standard MSE domain. Choose from the predefined list, or empty string if the observation doesn't fit a standard domain (in which case populate customLabel).",
  "value": { "type": "string", "enum": ["", "Appearance", "Behavior", "Speech", "Mood", "Affect", "Thought Process", "Thought Content", "Perception", "Cognition", "Insight and Judgment"] } },
{ "key": "customLabel",
  "description": "Custom domain label, used only when stdLabel is empty string. Empty string when a standard domain is selected.",
  "value": { "type": "string" } }
The two descriptions together teach a contract: pick a standard label, OR pick the empty-string sentinel and populate customLabel instead. enum alone can’t express that interplay; the descriptions carry it.

Anti-patterns

  • Don’t restate contentPrompt scope here. Section-wide “what to include” belongs in Recipe 1. Schema description is for this slot only.
  • Don’t restate writingStylePrompt voice here. Section-wide tone/register belongs in Recipe 2. If every field’s description says “use concise medical language”, move it up.
  • Don’t write a description longer than the rule it enforces. A leaf-field description is usually one sentence. If you’re writing three, the field probably needs to be split, or the rule belongs in miscPrompt.
  • Don’t restate what enum/pattern already enforces. “Use one of: PO, IV, IM …” in description is redundant when those are the enum values. Use description to explain why / when, not what.
  • Don’t leave descriptions empty when the field is non-obvious. Empty descriptions on cryptic field keys (prefix, trailer, stdLabel) make the model guess. The corpus consistently populates them.