Foliant

Templates / CV

CV

Two-column resume: contact and skills in the sidebar, experience and education as JSON lists. Fixed layout, so every applicant in a batch gets the same look.

1 page, A4. Rendered in 28 ms. 10 inputs, all optional.

Download .typ Open preview

Rendered CV template, first page
First page, rendered from the source below with the sample inputs.

Inputs

Everything variable comes in through sys.inputs. Missing keys fall back to sensible defaults, so an agent can send only what it knows.

KeySample value
education
JSON, 83 chars
[
  {
    "degree": "B.A. Communication Design",
    "org": "HTW Berlin",
    "period": "2012 to 2016"
  }
]
emailnora@example.com
experience
JSON, 530 chars
[
  {
    "role": "Lead Product Designer",
    "org": "Meridian Studio GmbH",
    "period": "2022 to today",
    "text": "Own the design system used by four product teams. Cut component drift by introducing tokens and a single documented library."
  },
  {
    "role": "Product Designer",
    "org": "Northwind Traders",
    "period": "2018 to 2022",
    "text": "Designed the B2B ordering portal end to end; conversion from quote to order rose 23 %."
  },
  {
    "role": "UI Designer",
    "org": "Freelance",
    "period": "2016 to 2018",
    "text": "Interfaces and print collateral for twelve small companies."
  }
]
headlineProduct designer, design systems
locationBerlin
nameNora Steinfeld
phone+49 170 000 0000
skills
JSON, 121 chars
[
  "Design systems",
  "Figma",
  "Typst and print",
  "Accessibility (WCAG 2.2)",
  "Design tokens",
  "User research",
  "German, English"
]
summaryEight years designing B2B software. I build design systems that engineering teams adopt, and I write the docs that make them stick.
websitenorasteinfeld.example

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 cv.pdf -d @- <<'JSON'
{ "template": "cv.typ",
  "inputs": {
    "education": "[{\"degree\":\"B.A. Communication Design\",\"org\":\"HTW Berlin\",\"period\":\"2012 to 2016\"}]",
    "email": "nora@example.com",
    "experience": "[{\"role\":\"Lead Product Designer\",\"org\":\"Meridian Studio GmbH\",\"period\":\"2022 to today\",\"text\":\"Own the design system used by four product teams. Cut component drift by introducing tokens and a single documented library.\"},{\"role\":\"Product Designer\",\"org\":\"Northwind Traders\",\"period\":\"2018 to 2022\",\"text\":\"Designed the B2B ordering portal end to end; conversion from quote to order rose 23 %.\"},{\"role\":\"UI Designer\",\"org\":\"Freelance\",\"period\":\"2016 to 2018\",\"text\":\"Interfaces and print collateral for twelve small companies.\"}]",
    "headline": "Product designer, design systems",
    "location": "Berlin",
    "name": "Nora Steinfeld",
    "phone": "+49 170 000 0000",
    "skills": "[\"Design systems\",\"Figma\",\"Typst and print\",\"Accessibility (WCAG 2.2)\",\"Design tokens\",\"User research\",\"German, English\"]",
    "summary": "Eight years designing B2B software. I build design systems that engineering teams adopt, and I write the docs that make them stick.",
    "website": "norasteinfeld.example"
  } }
JSON

Through MCP, render_document with template: "cv.typ" and the same inputs; get_template or fetch lists the keys.

Source

template.typ, 39 lines
#let input(k, default: "") = sys.inputs.at(k, default: default)
#let skills = json(bytes(input("skills", default: "[]")))
#let experience = json(bytes(input("experience", default: "[]")))
#let education = json(bytes(input("education", default: "[]")))
#set page(paper: "a4", margin: 0pt)
#set text(font: "Noto Sans", size: 10pt, fill: rgb("1a1917"))
#let label(t) = text(size: 8pt, fill: luma(110), tracking: 1pt)[#upper(t)]
#grid(columns: (62mm, 1fr), rows: 100%,
  block(fill: rgb("1a1917"), inset: (x: 10mm, y: 16mm), height: 100%, width: 100%)[
    #set text(fill: rgb("fffdf8"))
    #text(size: 22pt, weight: 700)[#input("name")]
    #v(2mm)
    #text(size: 10.5pt, fill: rgb("d7d1c3"))[#input("headline")]
    #v(10mm)
    #label[Contact] #v(2mm)
    #text(size: 9.5pt)[#input("email") \ #input("phone") \ #input("location") \ #input("website")]
    #v(10mm)
    #label[Skills] #v(2mm)
    #for s in skills [#text(size: 9.5pt)[#s] \ ]
  ],
  block(inset: (x: 14mm, y: 16mm))[
    #label[Profile] #v(2mm)
    #input("summary")
    #v(8mm)
    #label[Experience] #v(3mm)
    #for e in experience [
      #block(below: 5mm)[
        #grid(columns: (1fr, auto), [*#e.role*, #e.org], [#text(size: 9pt, fill: luma(110))[#e.period]])
        #v(1mm)
        #text(size: 9.5pt)[#e.text]
      ]
    ]
    #v(4mm)
    #label[Education] #v(3mm)
    #for e in education [
      #grid(columns: (1fr, auto), [*#e.degree*, #e.org], [#text(size: 9pt, fill: luma(110))[#e.period]])
    ]
  ])