Skip to content

typst-report-generator

Source: .opencode/skills/typst-report-generator/SKILL.md — site rebuilt 2026-09-05.


--- name: typst-report-generator description: Generate formal legal, regulatory, or contract documents and reports in Typst with a hanging clause engine and clinical serif styling. Use when asked to create or edit a legal report, regulatory submission, or contract document.


Typst Formal Report & Legal Document Skill

MANDATORY: run typst-planner first. No report is drafted or compiled until a typst-planner plan for this document has been emitted and signed off.

This skill governs the structure, geometry, typography, and clause formatting for legal contracts, formal reports, and statutory submissions in Typst.

1. Document Structure Sequence

Documents using this style must follow the strict section layout sequence in the main .typ file:

  1. Section 1: Page geometry (3cm margins), clinical serif typography, footnote/quote styling.
  2. Section 2: Clause engine (#let cl(num, body) = ...) and heading styles.
  3. Section 3: Page 1 Front Cover Sheet (top-left GREYSCALE logo, right-aligned title & metadata block, imprint footer, #pagebreak()).
  4. Section 4: Page 2+ geometry restore (4.5cm left margin for hanging numbers, running headers & footers).
  5. Section 5: Dynamic Table of Contents (#outline(...), #pagebreak()).
  6. Section 6: Report Content using #cl("P.1", [...]), #cl("1.1.1", [...]), etc.

1a. GREY SCALE MANDATE (all generated documents)

  • Grey scale only, end to end: every element (text, rules, table strokes, fills, headings, subtitles) is black or a shade of grey (luma(...)); NEVER emit colour.
  • Greyscale logo: cover logo is rendered with #image-grayscale(read("LOGO.png", encoding: none), width: 2.4cm) from @preview/grayness:0.7.0. Never use plain #image(...) for the logo. Ensure LOGO.png is present in the compilation directory.

2. Clause Engine Rules

  • Level Calculation: let level = segments.len() - 1
  • Primary Clauses (Level 0): Hang in left margin (dx: -2.2cm).
  • Sub-Clauses (Level 1+): Indented automatically by level * 0.6cm.

3. Typst Manual & Reference

Before drafting or when unsure of any Typst function, parameter, or syntax, consult the local, searchable mirror of the official Typst documentation at:

..\_typst-manual\
  • Function/element/type reference (e.g. #outline, #counter, #block, #grid, #set, #pagebreak, #text, cl engines, footnotes): search the Rust doc comments under _typst-manual\typst-src\crates\typst-library\src\ — every library item's full documentation and examples live there directly above its definition.
  • Language / syntax / scripting (#let, #set, #show, markup, math, context): _typst-manual\typst-src\docs\content\reference\language\*.typ and tutorial\.
  • Tutorials & guides: _typst-manual\typst-src\docs\content\tutorial\ and guides\.

See _typst-manual\README.md for lookup guidance.

Self-Learning: Runtime Environment Probe (RUN FIRST)

Before generating ANY document, probe the actual environment so you never ship a font or package that does not exist (Typst silently falls back, causing font discrepancies between the preview and the intended design):

powershell -ExecutionPolicy Bypass -File "..\_typst-manual\probe-fonts.ps1"

Read the output and the persisted report _typst-manual\font-probe-report.json. Then:

  • Rewrite every font stack so its FIRST member is an installed font from the report (e.g. this machine lacks Linux Libertine/Liberation Serif, so prefer a real installed serif such as Libertinus Serif, Georgia, Cambria, Palatino Linotype, or Times New Roman). Never leave a missing font as the leading choice.
  • Verify each @preview/... import is reported as cached; if missing, note that compilation needs network or the package must be cached first.
  • Only after resolving fonts/packages should you compile and generate the preview.

4. Compilation & Native Preview Workflow

Whenever generating or editing a report with this skill, you MUST compile the document into high-resolution PNGs and generate an interactive Carousel Artifact so the user can preview it natively in a local previews\ folder:

Step 1: Compile to PNG in Artifact Directory

typst compile report.typ "previews\report-page-{0p}.png" --ppi 144

Step 2: Create a Markdown Artifact (document_preview.md) Set UserFacing: true and output a markdown preview referencing the PNGs by relative path.

# Native Document Preview

````carousel
![Page 1](previews/report-page-01.png)
<!-- slide -->
![Page 2](previews/report-page-02.png)
````

5. Session learnings (14-08-2026)

  • Verbatim letter as a front section: when a letter of instruction must be reproduced inside a report, put it right after the TOC as an UNNUMBERED heading (#heading(numbering: none)[The Letter of Instruction]) so the report's own numbering (1. Parties and Dispute ...) is untouched; fence the quoted material with #block(stroke: (left: 2.5pt + black), inset: (left: 14pt)) at 9.5pt. Never re-use a global #set heading(numbering: none) in the middle of the document — it kills numbering for everything after it.
  • #include "x.typ" cannot see cl / #lets from the main file (fresh scope). Either #eval(read("x.typ")) (BOM-sensitive, see below) or append the fragment into the main .typ programmatically.
  • BOM: PowerShell Set-Content -Encoding UTF8 and the opencode Write tool emit a UTF-8 BOM; eval(read(...)) fails on it ("the character \uFEFF is not valid in code"). Write fragments via Python io.open(..., newline="").
  • Smart quotes: Typst auto-converts straight quotes to U+201C/U+201D; console in extraction output is usually just the codepage — confirm real codepoints with get_text('rawdict') before "fixing" anything.
  • Extracting a PDF letter: use get_text('blocks') (paragraph boundaries); restore U+FFFD by context (\ufffd(?=\d) -> £, else -> '); join lines ending in - or U+00AD before paragraphising; drop "Page N of M" markers.
  • One schedule per page: emit #pagebreak() before each = Schedule N heading.
  • Renumbering clauses: grep for dangling "see clause N" pointers (e.g. S6.7 -> clause 4.1) after any clause deletion.
  • Greyscale cover logo (mandate): #image-grayscale(read("LOGO.png", encoding: none), width: 2.4cm) with LOGO.png in the compile dir; verify greyscale by pixel sampling (0 non-greyscale samples expected).
  • Probe fonts first (see section 3): Libertinus Serif / Arial installed; grayness 0.7.0 cached.