Templates / Meeting minutes
Meeting minutes
Attendees, agenda items with decisions, and an action table with owners and due dates. The kind of document an agent writes after a call and sends before anyone forgets.
1 page, A4. Rendered in 40 ms. 8 inputs, all optional.
Inputs
Everything variable comes in through sys.inputs. Missing keys fall back to sensible defaults, so an agent can send only what it knows.
| Key | Sample value |
|---|---|
absent | JSON, 26 chars |
actions | JSON, 223 chars |
attendees | JSON, 103 chars |
date | 28 September 2026, 10:00 to 10:45 |
items | JSON, 527 chars |
location | Video call |
meeting | Portal redesign, weekly sync |
next | 5 October 2026, 10:00 |
Render it
After copying the template into your account:
curl -X POST https://api.foliant.dev/v1/render \
-H "Authorization: Bearer $FOLIANT_API_KEY" \
-H "Content-Type: application/json" \
-o minutes.pdf -d @- <<'JSON'
{ "template": "minutes.typ",
"inputs": {
"absent": "[\"Jonas Klein (Meridian)\"]",
"actions": "[{\"what\":\"Send revised checkout error copy\",\"who\":\"Tom\",\"due\":\"2 Oct\"},{\"what\":\"Confirm test participants and rooms\",\"who\":\"Priya\",\"due\":\"3 Oct\"},{\"what\":\"Update project plan with scope freeze\",\"who\":\"Mara\",\"due\":\"30 Sep\"}]",
"attendees": "[\"Lena Hartmann (Northwind)\",\"Mara Ehrlich (Meridian)\",\"Tom Weber (Meridian)\",\"Priya Nair (Northwind)\"]",
"date": "28 September 2026, 10:00 to 10:45",
"items": "[{\"title\":\"Milestone 2 review\",\"notes\":\"Key flows approved with minor copy changes. Checkout error states need one more round.\",\"decision\":\"M2 accepted; copy fixes bundled into M3.\"},{\"title\":\"Usability test\",\"notes\":\"Six participants recruited. Sessions planned for the week of 6 October.\",\"decision\":\"Go ahead; Northwind provides two internal users.\"},{\"title\":\"Launch date\",\"notes\":\"Marketing wants 15 November. Engineering estimates 10 November for feature complete.\",\"decision\":\"Keep 15 November, freeze scope after M3.\"}]",
"location": "Video call",
"meeting": "Portal redesign, weekly sync",
"next": "5 October 2026, 10:00"
} }
JSON
Through MCP, render_document with template: "minutes.typ" and the same inputs; get_template or fetch lists the keys.
Source
template.typ, 31 lines
#let input(k, default: "") = sys.inputs.at(k, default: default)
#let j(k) = json(bytes(input(k, default: "[]")))
#set page(paper: "a4", margin: 22mm, footer: context [#set text(size: 8.5pt, fill: luma(110)); #input("meeting") #h(1fr) #counter(page).display()])
#set text(font: "Noto Sans", size: 10pt, fill: rgb("1a1917"))
#text(size: 20pt, weight: 700)[Minutes]
#v(1mm)
#text(size: 12pt)[#input("meeting")]
#v(1mm)
#text(fill: luma(110))[#input("date") · #input("location")]
#v(6mm)
#grid(columns: (1fr, 1fr), gutter: 10mm,
[#text(size: 8pt, fill: luma(110), tracking: 1pt)[ATTENDEES] \ #j("attendees").join(", ")],
[#text(size: 8pt, fill: luma(110), tracking: 1pt)[ABSENT] \ #if j("absent").len() == 0 [none] else [#j("absent").join(", ")]])
#v(8mm)
#for (i, it) in j("items").enumerate() [
#block(below: 6mm)[
#text(weight: 700)[#(i + 1). #it.title]
#v(1.5mm)
#it.notes
#v(1.5mm)
#block(fill: rgb("f3efe6"), inset: 8pt, width: 100%, radius: 2pt)[#text(size: 9.5pt)[*Decision:* #it.decision]]
]
]
#text(size: 8pt, fill: luma(110), tracking: 1pt)[ACTIONS]
#v(2mm)
#table(columns: (1fr, auto, auto), inset: 7pt, stroke: (x, y) => if y == 0 { (bottom: 0.8pt) } else { (bottom: 0.3pt + luma(200)) },
[*What*], [*Who*], [*Due*],
..j("actions").map(a => (a.what, a.who, a.due)).flatten())
#v(8mm)
#text(fill: luma(110))[Next meeting: #input("next")]