Skip to main content

Document Generation: Customizing Sections — Best Practices

Best practices for customizing document generation in the Corti API — choosing the right customization lever, writing effective prompts, and using output schemas for reliable, consistent documents.

Overview

Corti document templates are built from sections, each carrying its own heading, prompts, and output schema. The customization surface lets you change how any section behaves — without rebuilding templates from scratch.

Customization works through three levers:

Lever

Where

Persistence

Use when

1. Use as-is

Reference a section or template by its UUID

n/a

The resource already does what you need

2. Inherit

inheritFromId when creating your own section or template

Persistent, versioned — and it keeps tracking Corti's improvements on fields you didn't override

The same customization applies to every call (e.g. per organization, customer, or specialty)

3. Runtime overrides

POST /documents request (Paths 2 and 3)

Ephemeral — the request is snapshotted for traceability, but the base resource is untouched

The customization varies between calls (e.g. per user, per encounter)

💡 Rule of thumb: if the same tweak applies to every call from this customer, create an inheriting resource. If it varies call to call, override at runtime.

The Override Fields

Whether you inherit persistently or override at runtime, the fields are the same:

Field

Purpose

heading

Override the section heading (title), e.g. Subjective → Anamnesis

instructions.contentPrompt

Guides what input content belongs in the section

instructions.writingStylePrompt

Guides tone and style (e.g. telegraphic, plain language)

instructions.miscPrompt

Free-form additional instructions

outputSchema

Controls the section's output shape and rendering — typed, not free text

⚠️ Coming from the previous (Classic) system? The override fields map directly to their new equivalents — see the migration guide on docs.corti.ai for the full mapping.

Classic field

New equivalent

nameOverride

heading

contentOverride

instructions.contentPrompt

writingStyleOverride

instructions.writingStylePrompt

additionalInstructionsOverride

instructions.miscPrompt

formatRuleOverride

outputSchema (typed schema — replaces free-text formatting)

Merge Rules — Important

Overrides obey different merge rules per field, wherever you apply them:

  • instructions is per-field partial — any prompt field you omit is inherited from the parent.

  • outputSchema is wholesale — your schema fully replaces the parent's schema. Partial schemas are not merged.

  • Runtime overrides can only patch sections already in the template — to add, remove, or reorder sections, use an assembly request (Path 3) instead.

Best Practices

1. Pick the Right Lever

Don't send the same override on every call forever — that's what inheritance is for. Persisting a customization as an inheriting section or template makes it versioned, publishable, and governed; runtime overrides are for genuine per-call variation.

2. Prevent Contradictions in Your Prompts

❌ Conflicting instructions

  • contentPrompt: "Include detailed lab results"

  • miscPrompt: "Do not include lab values"

✅ Best practice — ensure all override fields reinforce the same instruction set. Think of them as layers: content guidance → style guidance → detailed generation instructions. When these align, the model performs significantly better.

3. Use the Right Field for the Right Instruction

A common mistake is packing style, formatting, and content instructions all into miscPrompt.

❌ Not recommended — everything crammed into one field:

  • miscPrompt: "Write in a friendly tone, use numbered steps, avoid jargon, include medications, and format the output clearly."

✅ Recommended — one responsibility per field:

  • contentPrompt: "Include medications, dosage instructions, and home care tasks."

  • writingStylePrompt: "Plain language, numbered steps, action-oriented."

  • miscPrompt: "Provide instructions the pet owner can follow at home."

Separating responsibilities between fields improves clarity and model performance. The same applies inside an outputSchema: use the section's contentPrompt for overall scope, and each field's description for field-specific rules — descriptions are part of the prompt the model sees, not just metadata.

4. Be Explicit in Your Instructions

Be direct. The model performs best when instructions clearly define what to include, what to exclude, the desired tone, and the expected format.

❌ Vague: "Write a summary of the visit"

✅ Explicit: "Include the presenting complaint, symptom duration, and relevant history. Exclude lab values and technical medical terminology. Write 2–3 sentences in plain language suitable for a pet owner."

5. Use Output Schemas Instead of Free-Text Formatting Instructions

Instead of pleading for a format in prose, declare it in the outputSchema — it's typed, enforced, and unlocks structured output. Common patterns:

You want

Schema

Running paragraph

{ "type": "string" } — pair with contentPrompt/writingStylePrompt

Bullet points

{ "type": "array", "itemFormat": "- {item}\n", "items": { "type": "string" } }

Fixed subheadings

{ "type": "object" } with fields[] for each subheading and fieldFormat controlling rendering

One value from a closed set

string • enum (e.g. disposition: admit / discharge / transfer)

Remember: outputSchema overrides are wholesale — submit the full schema, not a partial patch.

6. Control the Empty State

When the source material has nothing relevant for a section, don't leave the output to chance:

  • Set default on string/number/boolean nodes (e.g. "Not discussed", "Nil")

  • Set fallbackString on array/object schemas for a meaningful placeholder instead of an empty string

This keeps the document's structure stable for downstream consumers.

Worked Example: Custom SOAP + Client Summary

A Corti team member built a demo app for veterinary use: one SOAP note for the clinic, and one client-facing summary generated from the same SOAP building blocks — with sections re-tuned for pet owners.

The SOAP note needs no customization — just reference the stored SOAP template (Path 1):

{
"outputLanguage": "en-US",
"interactionId": "<your-interaction-id>",
"templateRef": { "templateId": "<soap-template-id>" }
}

The client summary assembles three standard sections (resolved via LIST /documents/sections?lang=en, e.g. label family:corti-subjective) and overrides each (Path 3):

{
"outputLanguage": "en-US",
"interactionId": "<your-interaction-id>",
"assemblyTemplate": {
"name": "Client summary",
"sectionRefs": [
{
"sectionId": "<subjective-section-id>",
"overrides": {
"heading": "Visit Overview",
"instructions": {
"contentPrompt": "Include: reason for visit, presenting complaint, relevant history, patient signalment. Exclude: detailed physical exam findings, lab values, technical medical terms.",
"writingStylePrompt": "Warm, clear, plain language suitable for pet owners. Avoid medical jargon.",
"miscPrompt": "Write a brief, friendly summary of why the pet was brought in today. IMPORTANT: Use ONLY the facts provided. Do NOT invent or assume symptoms. 2-3 sentences."
}
}
},
{
"sectionId": "<assessment-section-id>",
"overrides": {
"heading": "What We Found",
"instructions": {
"contentPrompt": "Include: diagnosis or working diagnosis, key exam findings explained simply, test results in plain language.",
"writingStylePrompt": "Reassuring, clear, plain language for pet owners"
}
}
},
{
"sectionId": "<plan-section-id>",
"overrides": {
"heading": "Care Instructions",
"instructions": {
"contentPrompt": "Include: medications with simple dosing instructions, home care tasks, dietary changes, activity restrictions.",
"writingStylePrompt": "Action-oriented, numbered steps, plain language"
}
}
}
]
}
}

Why This Example Works Well

  • The sections align with clinical structure — Subjective → visit overview, Assessment → findings, Plan → care instructions. Clinical reasoning stays intact; only the output is adapted for a non-clinical audience.

  • Each override field serves one purpose — heading for the title, contentPrompt for what belongs (and what doesn't), writingStylePrompt for audience and tone, miscPrompt for behavioral constraints (factual grounding, length).

  • The instructions are explicit — include/exclude lists, audience, length. Clear constraints produce consistent documents.

Summary

When designing customizations:

✔ Pick the right lever — inherit for recurring, override at runtime for per-call

✔ Avoid contradictory instructions

✔ Use each field for its intended purpose

✔ Be explicit about what to include and exclude

✔ Prefer typed outputSchema over free-text formatting instructions

✔ Control empty states with default / fallbackString

✔ Store and reuse recurring customizations as inheriting resources

Where to Go Next

Did this answer your question?