Skip to content

std.document separates what a report contains from how it is laid out. A model fills a typed Report struct — title, takeaways, sections, conclusion — and a pure function render turns it into markdown. Section and table placement is structural, so you never regex-repair freeform model markdown again.

from std.document import Report, render

The classic failure mode of “ask a model for a markdown report” is that the model controls the structure as well as the content, so you end up parsing and repairing its output. Codebases grow an assemble_basic_answer / _assemble_report layer for exactly this. std.document inverts the control: the model supplies typed fields, and rendering is a deterministic Sema function you own. This is the standard-library face of documentation-as-artifact (spec §5.47) — structure lives in the language, prose comes from the model.

A Report is a flat struct of typed fields:

FieldTypeMeaning
titlestrDocument title (rendered as #)
contextstrItalic lead-in under the title
confidencef64Confidence in [0,1]; < 0 omits the confidence section
rationalestrProse shown alongside the confidence
takeawayslist[str]Bulleted key points
section_titleslist[str]Table-of-contents entries
sections_textstrThe rendered body sections
conclusionstrClosing section

render(r, nl) produces the markdown. The second argument, nl, is the newline separator — parametrized so the same renderer emits real newlines for output or a single-line form for tests:

from std.document import Report, render
r = Report(
title="Market Scan: Edge Inference",
context="Prepared for the Q3 review.",
confidence=0.87,
rationale="Corroborated across three independent sources.",
takeaways=["Latency is the dominant cost", "On-device wins for privacy"],
section_titles=["Landscape", "Costs"],
sections_text="## Landscape\n...\n## Costs\n...",
conclusion="Edge inference is viable for the target latency budget.",
)
md = render(r, "\n") # real newlines for output

Set confidence = -1.0 to drop the confidence block entirely — handy when a report is qualitative and a percentage would be misleading:

qualitative = Report(title="Notes", context="", confidence=-1.0, rationale="",
takeaways=["..."], section_titles=[], sections_text="",
conclusion="...")

See the full field and function reference in the generated std.document API reference.